Added sockets for notifications
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\DTOs\FlightStatData;
|
||||
use App\Models\Aircraft;
|
||||
use App\Models\IataEquipmentCode;
|
||||
use App\Models\Notification;
|
||||
use App\Models\UserFlight;
|
||||
use App\Services\FlightStatsService;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Console\Attributes\Description;
|
||||
use Illuminate\Console\Attributes\Signature;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
#[Signature('app:update-arrived-flights')]
|
||||
#[Description('Command description')]
|
||||
class UpdateArrivedFlights extends Command
|
||||
{
|
||||
|
||||
public function __construct(protected FlightStatsService $flightStats)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function notifyDataError(UserFlight $flight): void
|
||||
{
|
||||
Notification::create([
|
||||
'user_id' => $flight->user_id,
|
||||
'title' => "Auto update failed for {$flight->flight_number}",
|
||||
'body' => "There was an error fetching flight data for {$flight->flight_number}. Please manually check the aircraft type, registration and departure/arrival times.",
|
||||
'url' => '/flights/' . $flight->id . '/edit'
|
||||
]);
|
||||
|
||||
$flight->update(['auto_update' => false]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$now = now()->utc();
|
||||
|
||||
$userFlights = UserFlight::where('arrival_date', '<=', $now->copy()->subHour()->toDateTimeString())
|
||||
->where('auto_update', true)
|
||||
->whereNotNull('flight_number')
|
||||
->get();
|
||||
|
||||
$this->info("Found {$userFlights->count()} flights.");
|
||||
|
||||
foreach ($userFlights as $flight) {
|
||||
preg_match('/^([A-Z]{2,3})(\d+)$/i', $flight->flight_number, $matches);
|
||||
|
||||
if (empty($matches)) {
|
||||
$this->warn("Could not parse flight number: {$flight->flight_number}");
|
||||
$this->notifyDataError($flight);
|
||||
continue;
|
||||
}
|
||||
|
||||
$airlineCode = strtoupper($matches[1]);
|
||||
$flightNumber = $matches[2];
|
||||
|
||||
$arrivalDate = $flight->arrival_date->setTimezone($flight->arrivalAirport->timezone);
|
||||
|
||||
$data = $this->flightStats->fetchFlightData($airlineCode, $flightNumber, $arrivalDate);
|
||||
|
||||
if (!$data) {
|
||||
$this->warn("No flight data returned for {$airlineCode}{$flightNumber}");
|
||||
$this->notifyDataError($flight);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($data->departure_iata !== $flight->departureAirport->iata_code ||
|
||||
$data->arrival_iata !== $flight->arrivalAirport->iata_code) {
|
||||
$this->warn("Airport mismatch for {$airlineCode}{$flightNumber} — API: {$data->departure_iata}→{$data->arrival_iata}, expected: {$flight->departureAirport->iata_code}→{$flight->arrivalAirport->iata_code}");
|
||||
$this->notifyDataError($flight);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$updates = [];
|
||||
|
||||
if ($data->aircraft_registration && $data->aircraft_registration !== $flight->aircraft_registration) {
|
||||
$updates['aircraft_registration'] = $data->aircraft_registration;
|
||||
}
|
||||
|
||||
if ($data->estimated_departure_utc?->ne($flight->departure_date)) {
|
||||
$updates['departure_date'] = $data->estimated_departure_utc;
|
||||
}
|
||||
|
||||
if ($data->estimated_arrival_utc?->ne($flight->arrival_date)) {
|
||||
$updates['arrival_date'] = $data->estimated_arrival_utc;
|
||||
}
|
||||
|
||||
if ($data->equipment_iata) {
|
||||
$currentAircraft = $flight->aircraft;
|
||||
|
||||
if ($currentAircraft?->iata_code !== $data->equipment_iata) {
|
||||
$match = $this->flightStats->guessAircraftFromIata($data->equipment_iata);
|
||||
|
||||
if ($match) {
|
||||
$updates['aircraft_id'] = $match->id;
|
||||
} else {
|
||||
Log::info("No aircraft match for IATA code {$data->equipment_iata} on flight {$airlineCode}{$flightNumber}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($updates)) {
|
||||
$flight->update($updates);
|
||||
$this->info("Updated flight {$airlineCode}{$flightNumber}: " . implode(', ', array_keys($updates)));
|
||||
|
||||
$changeDescriptions = [];
|
||||
if (isset($updates['aircraft_registration'])) {
|
||||
$changeDescriptions[] = "Registration updated to {$updates['aircraft_registration']}";
|
||||
}
|
||||
if (isset($updates['departure_date'])) {
|
||||
$changeDescriptions[] = "Departure updated to {$updates['departure_date']}";
|
||||
}
|
||||
if (isset($updates['arrival_date'])) {
|
||||
$changeDescriptions[] = "Arrival updated to {$updates['arrival_date']}";
|
||||
}
|
||||
if (isset($updates['aircraft_id'])) {
|
||||
$aircraft = Aircraft::find($updates['aircraft_id']);
|
||||
$changeDescriptions[] = "Aircraft type updated to {$aircraft->display_name_short}";
|
||||
}
|
||||
|
||||
Notification::create([
|
||||
'user_id' => $flight->user_id,
|
||||
'title' => "Flight {$airlineCode}{$flightNumber} updated",
|
||||
'body' => implode("\n", $changeDescriptions),
|
||||
'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id,
|
||||
]);
|
||||
} else {
|
||||
$this->info("No changes for {$airlineCode}{$flightNumber}");
|
||||
|
||||
Notification::create([
|
||||
'user_id' => $flight->user_id,
|
||||
'title' => "Flight {$airlineCode}{$flightNumber} updated — no changes",
|
||||
'body' => "Your flight was completed and no updates were made to aircraft, registration, or departure/arrival times.",
|
||||
'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$flight->update(['auto_update' => false]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,42 +2,18 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\DTOs\FlightStatData;
|
||||
use App\Models\Aircraft;
|
||||
use App\Models\IataEquipmentCode;
|
||||
use App\Models\Notification;
|
||||
use App\Models\UserFlight;
|
||||
use App\Services\FlightStatsService;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Console\Attributes\Description;
|
||||
use Illuminate\Console\Attributes\Signature;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
#[Signature('app:update-departed-flights')]
|
||||
#[Description('Command description')]
|
||||
class UpdateDepartedFlights extends Command
|
||||
{
|
||||
|
||||
public function __construct(protected FlightStatsService $flightStats)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function notifyDataError(UserFlight $flight): void
|
||||
{
|
||||
Notification::create([
|
||||
'user_id' => $flight->user_id,
|
||||
'title' => "Auto update failed for {$flight->flight_number}",
|
||||
'body' => "There was an error fetching flight data for {$flight->flight_number}. Please manually check the aircraft type, registration and departure/arrival times.",
|
||||
'url' => '/flights/' . $flight->id . '/edit'
|
||||
]);
|
||||
|
||||
$flight->update(['auto_update' => false]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
@@ -45,108 +21,20 @@ class UpdateDepartedFlights extends Command
|
||||
{
|
||||
$now = now()->utc();
|
||||
|
||||
$userFlights = UserFlight::where('arrival_date', '<=', $now->copy()->subHour()->toDateTimeString())
|
||||
->where('auto_update', true)
|
||||
->whereNotNull('flight_number')
|
||||
$now = now()->utc();
|
||||
|
||||
$userFlights = UserFlight::where('departure_date', '<=', $now->toDateTimeString())
|
||||
->where('departure_date', '>', $now->copy()->subMinute()->toDateTimeString())
|
||||
->get();
|
||||
|
||||
$this->info("Found {$userFlights->count()} flights.");
|
||||
|
||||
foreach ($userFlights as $flight) {
|
||||
preg_match('/^([A-Z]{2,3})(\d+)$/i', $flight->flight_number, $matches);
|
||||
|
||||
if (empty($matches)) {
|
||||
$this->warn("Could not parse flight number: {$flight->flight_number}");
|
||||
$this->notifyDataError($flight);
|
||||
continue;
|
||||
}
|
||||
|
||||
$airlineCode = strtoupper($matches[1]);
|
||||
$flightNumber = $matches[2];
|
||||
|
||||
$arrivalDate = $flight->arrival_date->setTimezone($flight->arrivalAirport->timezone);
|
||||
|
||||
$data = $this->flightStats->fetchFlightData($airlineCode, $flightNumber, $arrivalDate);
|
||||
|
||||
if (!$data) {
|
||||
$this->warn("No flight data returned for {$airlineCode}{$flightNumber}");
|
||||
$this->notifyDataError($flight);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($data->departure_iata !== $flight->departureAirport->iata_code ||
|
||||
$data->arrival_iata !== $flight->arrivalAirport->iata_code) {
|
||||
$this->warn("Airport mismatch for {$airlineCode}{$flightNumber} — API: {$data->departure_iata}→{$data->arrival_iata}, expected: {$flight->departureAirport->iata_code}→{$flight->arrivalAirport->iata_code}");
|
||||
$this->notifyDataError($flight);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$updates = [];
|
||||
|
||||
if ($data->aircraft_registration && $data->aircraft_registration !== $flight->aircraft_registration) {
|
||||
$updates['aircraft_registration'] = $data->aircraft_registration;
|
||||
}
|
||||
|
||||
if ($data->estimated_departure_utc?->ne($flight->departure_date)) {
|
||||
$updates['departure_date'] = $data->estimated_departure_utc;
|
||||
}
|
||||
|
||||
if ($data->estimated_arrival_utc?->ne($flight->arrival_date)) {
|
||||
$updates['arrival_date'] = $data->estimated_arrival_utc;
|
||||
}
|
||||
|
||||
if ($data->equipment_iata) {
|
||||
$currentAircraft = $flight->aircraft;
|
||||
|
||||
if ($currentAircraft?->iata_code !== $data->equipment_iata) {
|
||||
$match = $this->flightStats->guessAircraftFromIata($data->equipment_iata);
|
||||
|
||||
if ($match) {
|
||||
$updates['aircraft_id'] = $match->id;
|
||||
} else {
|
||||
Log::info("No aircraft match for IATA code {$data->equipment_iata} on flight {$airlineCode}{$flightNumber}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($updates)) {
|
||||
$flight->update($updates);
|
||||
$this->info("Updated flight {$airlineCode}{$flightNumber}: " . implode(', ', array_keys($updates)));
|
||||
|
||||
$changeDescriptions = [];
|
||||
if (isset($updates['aircraft_registration'])) {
|
||||
$changeDescriptions[] = "Registration updated to {$updates['aircraft_registration']}";
|
||||
}
|
||||
if (isset($updates['departure_date'])) {
|
||||
$changeDescriptions[] = "Departure updated to {$updates['departure_date']}";
|
||||
}
|
||||
if (isset($updates['arrival_date'])) {
|
||||
$changeDescriptions[] = "Arrival updated to {$updates['arrival_date']}";
|
||||
}
|
||||
if (isset($updates['aircraft_id'])) {
|
||||
$aircraft = Aircraft::find($updates['aircraft_id']);
|
||||
$changeDescriptions[] = "Aircraft type updated to {$aircraft->display_name_short}";
|
||||
}
|
||||
|
||||
Notification::create([
|
||||
'user_id' => $flight->user_id,
|
||||
'title' => "Flight {$airlineCode}{$flightNumber} updated",
|
||||
'body' => implode("\n", $changeDescriptions),
|
||||
'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id,
|
||||
]);
|
||||
} else {
|
||||
$this->info("No changes for {$airlineCode}{$flightNumber}");
|
||||
|
||||
Notification::create([
|
||||
'user_id' => $flight->user_id,
|
||||
'title' => "Flight {$airlineCode}{$flightNumber} updated — no changes",
|
||||
'body' => "Your flight was completed and no updates were made to aircraft, registration, or departure/arrival times.",
|
||||
'url' => '/u/'. $flight->user->name . '/flight/'. $flight->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$flight->update(['auto_update' => false]);
|
||||
$flight->touch();
|
||||
}
|
||||
|
||||
$this->info("Touching flight {$flight->id}");
|
||||
$result = $flight->touch();
|
||||
$this->info("Touch result: " . var_export($result, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Notification;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class NotificationCreated implements ShouldBroadcast
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(public Notification $notification) {}
|
||||
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('App.Models.User.' . $this->notification->user_id),
|
||||
];
|
||||
}
|
||||
|
||||
public function broadcastAs(): string
|
||||
{
|
||||
return 'notification.created';
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Events\NotificationCreated;
|
||||
use App\Models\Followee;
|
||||
use App\Models\Notification;
|
||||
use App\Models\User;
|
||||
|
||||
@@ -34,6 +34,7 @@ class FlightObserver
|
||||
*/
|
||||
public function updated(UserFlight $flight): void
|
||||
{
|
||||
\Log::info('Observer fired for flight ' . $flight->id);
|
||||
$flight->user->calculateAchievements();
|
||||
$this->clearCache($flight);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Events\NotificationCreated;
|
||||
use App\Models\Notification;
|
||||
|
||||
class NotificationObserver
|
||||
{
|
||||
public function created(Notification $notification): void
|
||||
{
|
||||
\Log::info('Notification created: ' . $notification->id);
|
||||
broadcast(new NotificationCreated($notification));
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,11 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Airline;
|
||||
use App\Models\Notification;
|
||||
use App\Models\UserFlight;
|
||||
use App\Observers\AirlineObserver;
|
||||
use App\Observers\FlightObserver;
|
||||
use App\Observers\NotificationObserver;
|
||||
use Illuminate\Support\Facades\Vite;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
@@ -30,6 +32,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
Vite::prefetch(concurrency: 3);
|
||||
UserFlight::observe(FlightObserver::class);
|
||||
Airline::observe(AirlineObserver::class);
|
||||
Notification::observe(NotificationObserver::class);
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return $request->user('sanctum')
|
||||
? Limit::perMinute(60)->by($request->user('sanctum')->id)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services\Achievements;
|
||||
|
||||
use App\Events\NotificationCreated;
|
||||
use App\Models\Achievement;
|
||||
use App\Models\Notification;
|
||||
use App\Models\User;
|
||||
@@ -50,6 +51,8 @@ class AchievementService
|
||||
$this->user = $user;
|
||||
$this->achievementCache = Achievement::all()->keyBy('internal_name');
|
||||
|
||||
// In calculateAchievements (or wherever createAchievementNotification is called from)
|
||||
\Log::info('calculateAchievements running for user ' . $user->id);
|
||||
// Load once with every relationship any checker could need
|
||||
$this->flights = $user->flights()->with([
|
||||
'airline.alliance',
|
||||
|
||||
@@ -22,6 +22,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
channels: __DIR__.'/../routes/channels.php',
|
||||
health: '/up',
|
||||
apiPrefix: '',
|
||||
)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"ext-pdo": "*",
|
||||
"inertiajs/inertia-laravel": "^2.0",
|
||||
"laravel/framework": "^13.0",
|
||||
"laravel/reverb": "^1.0",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^3.0",
|
||||
"spatie/laravel-permission": "^8.0",
|
||||
|
||||
Generated
+906
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "2fab3a0703fff56cedb9d4c9b650e2fc",
|
||||
"content-hash": "396baef77a56f5dfee4ec5d1bb9c0c52",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
@@ -135,6 +135,136 @@
|
||||
],
|
||||
"time": "2024-02-09T16:56:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "clue/redis-protocol",
|
||||
"version": "v0.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/clue/redis-protocol.git",
|
||||
"reference": "6f565332f5531b7722d1e9c445314b91862f6d6c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/clue/redis-protocol/zipball/6f565332f5531b7722d1e9c445314b91862f6d6c",
|
||||
"reference": "6f565332f5531b7722d1e9c445314b91862f6d6c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Clue\\Redis\\Protocol\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@lueck.tv"
|
||||
}
|
||||
],
|
||||
"description": "A streaming Redis protocol (RESP) parser and serializer written in pure PHP.",
|
||||
"homepage": "https://github.com/clue/redis-protocol",
|
||||
"keywords": [
|
||||
"parser",
|
||||
"protocol",
|
||||
"redis",
|
||||
"resp",
|
||||
"serializer",
|
||||
"streaming"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/clue/redis-protocol/issues",
|
||||
"source": "https://github.com/clue/redis-protocol/tree/v0.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://clue.engineering/support",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/clue",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-08-07T11:06:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "clue/redis-react",
|
||||
"version": "v2.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/clue/reactphp-redis.git",
|
||||
"reference": "84569198dfd5564977d2ae6a32de4beb5a24bdca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/clue/reactphp-redis/zipball/84569198dfd5564977d2ae6a32de4beb5a24bdca",
|
||||
"reference": "84569198dfd5564977d2ae6a32de4beb5a24bdca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"clue/redis-protocol": "^0.3.2",
|
||||
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
|
||||
"php": ">=5.3",
|
||||
"react/event-loop": "^1.2",
|
||||
"react/promise": "^3.2 || ^2.0 || ^1.1",
|
||||
"react/promise-timer": "^1.11",
|
||||
"react/socket": "^1.16"
|
||||
},
|
||||
"require-dev": {
|
||||
"clue/block-react": "^1.5",
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Clue\\React\\Redis\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering"
|
||||
}
|
||||
],
|
||||
"description": "Async Redis client implementation, built on top of ReactPHP.",
|
||||
"homepage": "https://github.com/clue/reactphp-redis",
|
||||
"keywords": [
|
||||
"async",
|
||||
"client",
|
||||
"database",
|
||||
"reactphp",
|
||||
"redis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/clue/reactphp-redis/issues",
|
||||
"source": "https://github.com/clue/reactphp-redis/tree/v2.8.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://clue.engineering/support",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/clue",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-01-03T16:18:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dflydev/dot-access-data",
|
||||
"version": "v3.0.3",
|
||||
@@ -508,6 +638,53 @@
|
||||
],
|
||||
"time": "2025-03-06T22:45:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "evenement/evenement",
|
||||
"version": "v3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/igorw/evenement.git",
|
||||
"reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
|
||||
"reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9 || ^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Evenement\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Igor Wiedler",
|
||||
"email": "igor@wiedler.ch"
|
||||
}
|
||||
],
|
||||
"description": "Événement is a very simple event dispatching library for PHP",
|
||||
"keywords": [
|
||||
"event-dispatcher",
|
||||
"event-emitter"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/igorw/evenement/issues",
|
||||
"source": "https://github.com/igorw/evenement/tree/v3.0.2"
|
||||
},
|
||||
"time": "2023-08-08T05:53:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fruitcake/php-cors",
|
||||
"version": "v1.4.0",
|
||||
@@ -1406,6 +1583,85 @@
|
||||
},
|
||||
"time": "2026-03-23T14:35:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/reverb",
|
||||
"version": "v1.10.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/reverb.git",
|
||||
"reference": "43a5c0a99b1aaba33dc32f97fcf51f182dd8c8ac"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/reverb/zipball/43a5c0a99b1aaba33dc32f97fcf51f182dd8c8ac",
|
||||
"reference": "43a5c0a99b1aaba33dc32f97fcf51f182dd8c8ac",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"clue/redis-react": "^2.6",
|
||||
"guzzlehttp/psr7": "^2.6",
|
||||
"illuminate/console": "^10.47|^11.0|^12.0|^13.0",
|
||||
"illuminate/contracts": "^10.47|^11.0|^12.0|^13.0",
|
||||
"illuminate/http": "^10.47|^11.0|^12.0|^13.0",
|
||||
"illuminate/support": "^10.47|^11.0|^12.0|^13.0",
|
||||
"laravel/prompts": "^0.1.15|^0.2.0|^0.3.0",
|
||||
"php": "^8.2",
|
||||
"pusher/pusher-php-server": "^7.2",
|
||||
"ratchet/rfc6455": "^0.4",
|
||||
"react/promise-timer": "^1.10",
|
||||
"react/socket": "^1.14",
|
||||
"symfony/console": "^6.0|^7.0|^8.0",
|
||||
"symfony/http-foundation": "^6.3|^7.0|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^8.36|^9.15|^10.8|^11.0",
|
||||
"pestphp/pest": "^2.0|^3.0|^4.0",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"ratchet/pawl": "^0.4.1",
|
||||
"react/async": "^4.2",
|
||||
"react/http": "^1.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Reverb\\ApplicationManagerServiceProvider",
|
||||
"Laravel\\Reverb\\ReverbServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Reverb\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
},
|
||||
{
|
||||
"name": "Joe Dixon",
|
||||
"email": "joe@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.",
|
||||
"keywords": [
|
||||
"WebSockets",
|
||||
"laravel",
|
||||
"real-time",
|
||||
"websocket"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/reverb/issues",
|
||||
"source": "https://github.com/laravel/reverb/tree/v1.10.2"
|
||||
},
|
||||
"time": "2026-05-10T15:47:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/sanctum",
|
||||
"version": "v4.3.1",
|
||||
@@ -3235,6 +3491,66 @@
|
||||
},
|
||||
"time": "2026-03-22T23:03:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pusher/pusher-php-server",
|
||||
"version": "7.2.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pusher/pusher-http-php.git",
|
||||
"reference": "4aa139ed2a2a805cd265449b691198beee1309d2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pusher/pusher-http-php/zipball/4aa139ed2a2a805cd265449b691198beee1309d2",
|
||||
"reference": "4aa139ed2a2a805cd265449b691198beee1309d2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"php": "^7.3|^8.0",
|
||||
"psr/log": "^1.0|^2.0|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"overtrue/phplint": "^2.3",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Pusher\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Library for interacting with the Pusher REST API",
|
||||
"keywords": [
|
||||
"events",
|
||||
"messaging",
|
||||
"php-pusher-server",
|
||||
"publish",
|
||||
"push",
|
||||
"pusher",
|
||||
"real time",
|
||||
"real-time",
|
||||
"realtime",
|
||||
"rest",
|
||||
"trigger"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/pusher/pusher-http-php/issues",
|
||||
"source": "https://github.com/pusher/pusher-http-php/tree/7.2.8"
|
||||
},
|
||||
"time": "2026-05-18T13:11:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
"version": "3.0.3",
|
||||
@@ -3433,6 +3749,595 @@
|
||||
},
|
||||
"time": "2025-12-14T04:43:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ratchet/rfc6455",
|
||||
"version": "v0.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ratchetphp/RFC6455.git",
|
||||
"reference": "9b05f371219cbaf9748b505f139617dd0715592b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/9b05f371219cbaf9748b505f139617dd0715592b",
|
||||
"reference": "9b05f371219cbaf9748b505f139617dd0715592b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"psr/http-factory-implementation": "^1.0",
|
||||
"symfony/polyfill-php80": "^1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/psr7": "^2.7",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"react/socket": "^1.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ratchet\\RFC6455\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Matt Bonneau",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "RFC6455 WebSocket protocol handler",
|
||||
"homepage": "http://socketo.me",
|
||||
"keywords": [
|
||||
"WebSockets",
|
||||
"rfc6455",
|
||||
"websocket"
|
||||
],
|
||||
"support": {
|
||||
"chat": "https://gitter.im/reactphp/reactphp",
|
||||
"issues": "https://github.com/ratchetphp/RFC6455/issues",
|
||||
"source": "https://github.com/ratchetphp/RFC6455/tree/v0.4.1"
|
||||
},
|
||||
"time": "2026-06-06T14:34:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/cache",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/cache.git",
|
||||
"reference": "d47c472b64aa5608225f47965a484b75c7817d5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b",
|
||||
"reference": "d47c472b64aa5608225f47965a484b75c7817d5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"react/promise": "^3.0 || ^2.0 || ^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\Cache\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "Async, Promise-based cache interface for ReactPHP",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"caching",
|
||||
"promise",
|
||||
"reactphp"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/cache/issues",
|
||||
"source": "https://github.com/reactphp/cache/tree/v1.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-30T15:59:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/dns",
|
||||
"version": "v1.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/dns.git",
|
||||
"reference": "7562c05391f42701c1fccf189c8225fece1cd7c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3",
|
||||
"reference": "7562c05391f42701c1fccf189c8225fece1cd7c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"react/cache": "^1.0 || ^0.6 || ^0.5",
|
||||
"react/event-loop": "^1.2",
|
||||
"react/promise": "^3.2 || ^2.7 || ^1.2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
|
||||
"react/async": "^4.3 || ^3 || ^2",
|
||||
"react/promise-timer": "^1.11"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\Dns\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "Async DNS resolver for ReactPHP",
|
||||
"keywords": [
|
||||
"async",
|
||||
"dns",
|
||||
"dns-resolver",
|
||||
"reactphp"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/dns/issues",
|
||||
"source": "https://github.com/reactphp/dns/tree/v1.14.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-18T19:34:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/event-loop",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/event-loop.git",
|
||||
"reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
|
||||
"reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcntl": "For signal handling support when using the StreamSelectLoop"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\EventLoop\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
|
||||
"keywords": [
|
||||
"asynchronous",
|
||||
"event-loop"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/event-loop/issues",
|
||||
"source": "https://github.com/reactphp/event-loop/tree/v1.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-17T20:46:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/promise",
|
||||
"version": "v3.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/promise.git",
|
||||
"reference": "23444f53a813a3296c1368bb104793ce8d88f04a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a",
|
||||
"reference": "23444f53a813a3296c1368bb104793ce8d88f04a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.12.28 || 1.4.10",
|
||||
"phpunit/phpunit": "^9.6 || ^7.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"React\\Promise\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
|
||||
"keywords": [
|
||||
"promise",
|
||||
"promises"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/promise/issues",
|
||||
"source": "https://github.com/reactphp/promise/tree/v3.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-19T18:57:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/promise-timer",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/promise-timer.git",
|
||||
"reference": "4f70306ed66b8b44768941ca7f142092600fafc1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/promise-timer/zipball/4f70306ed66b8b44768941ca7f142092600fafc1",
|
||||
"reference": "4f70306ed66b8b44768941ca7f142092600fafc1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3",
|
||||
"react/event-loop": "^1.2",
|
||||
"react/promise": "^3.2 || ^2.7.0 || ^1.2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"React\\Promise\\Timer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
|
||||
"homepage": "https://github.com/reactphp/promise-timer",
|
||||
"keywords": [
|
||||
"async",
|
||||
"event-loop",
|
||||
"promise",
|
||||
"reactphp",
|
||||
"timeout",
|
||||
"timer"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/promise-timer/issues",
|
||||
"source": "https://github.com/reactphp/promise-timer/tree/v1.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-04T14:27:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/socket",
|
||||
"version": "v1.17.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/socket.git",
|
||||
"reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08",
|
||||
"reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
|
||||
"php": ">=5.3.0",
|
||||
"react/dns": "^1.13",
|
||||
"react/event-loop": "^1.2",
|
||||
"react/promise": "^3.2 || ^2.6 || ^1.2.1",
|
||||
"react/stream": "^1.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
|
||||
"react/async": "^4.3 || ^3.3 || ^2",
|
||||
"react/promise-stream": "^1.4",
|
||||
"react/promise-timer": "^1.11"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\Socket\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
|
||||
"keywords": [
|
||||
"Connection",
|
||||
"Socket",
|
||||
"async",
|
||||
"reactphp",
|
||||
"stream"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/socket/issues",
|
||||
"source": "https://github.com/reactphp/socket/tree/v1.17.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-19T20:47:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/stream",
|
||||
"version": "v1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/stream.git",
|
||||
"reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d",
|
||||
"reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
|
||||
"php": ">=5.3.8",
|
||||
"react/event-loop": "^1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"clue/stream-filter": "~1.2",
|
||||
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\Stream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
|
||||
"keywords": [
|
||||
"event-driven",
|
||||
"io",
|
||||
"non-blocking",
|
||||
"pipe",
|
||||
"reactphp",
|
||||
"readable",
|
||||
"stream",
|
||||
"writable"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/stream/issues",
|
||||
"source": "https://github.com/reactphp/stream/tree/v1.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-11T12:45:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
"version": "1.93.1",
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Broadcaster
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default broadcaster that will be used by the
|
||||
| framework when an event needs to be broadcast. You may set this to
|
||||
| any of the connections defined in the "connections" array below.
|
||||
|
|
||||
| Supported: "reverb", "pusher", "ably", "redis", "log", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('BROADCAST_CONNECTION', 'null'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Broadcast Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the broadcast connections that will be used
|
||||
| to broadcast events to other systems or over WebSockets. Samples of
|
||||
| each available type of connection are provided inside this array.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'reverb' => [
|
||||
'driver' => 'reverb',
|
||||
'key' => env('REVERB_APP_KEY'),
|
||||
'secret' => env('REVERB_APP_SECRET'),
|
||||
'app_id' => env('REVERB_APP_ID'),
|
||||
'options' => [
|
||||
'host' => env('REVERB_HOST'),
|
||||
'port' => env('REVERB_PORT', 443),
|
||||
'scheme' => env('REVERB_SCHEME', 'https'),
|
||||
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'client_options' => [
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||
],
|
||||
],
|
||||
|
||||
'pusher' => [
|
||||
'driver' => 'pusher',
|
||||
'key' => env('PUSHER_APP_KEY'),
|
||||
'secret' => env('PUSHER_APP_SECRET'),
|
||||
'app_id' => env('PUSHER_APP_ID'),
|
||||
'options' => [
|
||||
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
|
||||
'port' => env('PUSHER_PORT', 443),
|
||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
||||
'encrypted' => true,
|
||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'client_options' => [
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||
],
|
||||
],
|
||||
|
||||
'ably' => [
|
||||
'driver' => 'ably',
|
||||
'key' => env('ABLY_KEY'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'driver' => 'log',
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'null',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Reverb Server
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default server used by Reverb to handle
|
||||
| incoming messages as well as broadcasting message to all your
|
||||
| connected clients. At this time only "reverb" is supported.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('REVERB_SERVER', 'reverb'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Reverb Servers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define details for each of the supported Reverb servers.
|
||||
| Each server has its own configuration options that are defined in
|
||||
| the array below. You should ensure all the options are present.
|
||||
|
|
||||
*/
|
||||
|
||||
'servers' => [
|
||||
|
||||
'reverb' => [
|
||||
'host' => env('REVERB_SERVER_HOST', '0.0.0.0'),
|
||||
'port' => env('REVERB_SERVER_PORT', 8080),
|
||||
'path' => env('REVERB_SERVER_PATH', ''),
|
||||
'hostname' => env('REVERB_HOST'),
|
||||
'options' => [
|
||||
'tls' => [],
|
||||
],
|
||||
'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000),
|
||||
'scaling' => [
|
||||
'enabled' => env('REVERB_SCALING_ENABLED', false),
|
||||
'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
|
||||
'server' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
'timeout' => env('REDIS_TIMEOUT', 60),
|
||||
],
|
||||
],
|
||||
'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
|
||||
'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Reverb Applications
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define how Reverb applications are managed. If you choose
|
||||
| to use the "config" provider, you may define an array of apps which
|
||||
| your server will support, including their connection credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'apps' => [
|
||||
|
||||
'provider' => 'config',
|
||||
|
||||
'apps' => [
|
||||
[
|
||||
'key' => env('REVERB_APP_KEY'),
|
||||
'secret' => env('REVERB_APP_SECRET'),
|
||||
'app_id' => env('REVERB_APP_ID'),
|
||||
'options' => [
|
||||
'host' => env('REVERB_HOST'),
|
||||
'port' => env('REVERB_PORT', 443),
|
||||
'scheme' => env('REVERB_SCHEME', 'https'),
|
||||
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'allowed_origins' => ['*'],
|
||||
'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60),
|
||||
'activity_timeout' => env('REVERB_APP_ACTIVITY_TIMEOUT', 30),
|
||||
'max_connections' => env('REVERB_APP_MAX_CONNECTIONS'),
|
||||
'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
|
||||
'accept_client_events_from' => env('REVERB_APP_ACCEPT_CLIENT_EVENTS_FROM', 'members'),
|
||||
'rate_limiting' => [
|
||||
'enabled' => env('REVERB_APP_RATE_LIMITING_ENABLED', false),
|
||||
'max_attempts' => env('REVERB_APP_RATE_LIMIT_MAX_ATTEMPTS', 60),
|
||||
'decay_seconds' => env('REVERB_APP_RATE_LIMIT_DECAY_SECONDS', 60),
|
||||
'terminate_on_limit' => env('REVERB_APP_RATE_LIMIT_TERMINATE', false),
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
Generated
+209
-8
@@ -11,12 +11,14 @@
|
||||
"echarts": "^6.0.0",
|
||||
"flag-icons": "^7.5.0",
|
||||
"maplibre-gl": "^5.22.0",
|
||||
"pinia": "^3.0.4",
|
||||
"vue-echarts": "^8.0.1",
|
||||
"vue3-apexcharts": "^1.11.1",
|
||||
"vuetify": "^4.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@inertiajs/vue3": "^2.0.0",
|
||||
"@laravel/echo-vue": "^2.3.7",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@types/geojson": "^7946.0.16",
|
||||
@@ -25,10 +27,12 @@
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"autoprefixer": "^10.4.12",
|
||||
"axios": "^1.11.0",
|
||||
"concurrently": "^9.0.1",
|
||||
"concurrently": "^9.2.3",
|
||||
"cross-var": "^1.1.0",
|
||||
"laravel-echo": "^2.3.7",
|
||||
"laravel-vite-plugin": "^3.0.0",
|
||||
"postcss": "^8.4.31",
|
||||
"pusher-js": "^8.5.0",
|
||||
"sass-embedded": "^1.100.0",
|
||||
"tailwindcss": "^3.2.1",
|
||||
"typescript": "^6.0.2",
|
||||
@@ -240,6 +244,29 @@
|
||||
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@laravel/echo-vue": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@laravel/echo-vue/-/echo-vue-2.3.7.tgz",
|
||||
"integrity": "sha512-52lOuge5JdGKjGs1bgzrgbubh6mGATTB2kpQsf4TVXXQez0xF3joPcSoyFv9YAqcn8wxwxUdm2dStTsqfL0r2A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pusher-js": "*",
|
||||
"socket.io-client": "*",
|
||||
"vue": "^3.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"pusher-js": {
|
||||
"optional": true
|
||||
},
|
||||
"socket.io-client": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/jsonlint-lines-primitives": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
|
||||
@@ -1456,6 +1483,39 @@
|
||||
"@vue/shared": "3.5.38"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
"version": "7.7.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz",
|
||||
"integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-kit": "^7.7.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-kit": {
|
||||
"version": "7.7.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz",
|
||||
"integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-shared": "^7.7.10",
|
||||
"birpc": "^2.3.0",
|
||||
"hookable": "^5.5.3",
|
||||
"mitt": "^3.0.1",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
"speakingurl": "^14.0.1",
|
||||
"superjson": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-shared": {
|
||||
"version": "7.7.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz",
|
||||
"integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"rfdc": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.5.38",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz",
|
||||
@@ -2666,6 +2726,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/birpc": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
|
||||
"integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
|
||||
@@ -2939,15 +3008,15 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
|
||||
"integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
|
||||
"version": "9.2.3",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.3.tgz",
|
||||
"integrity": "sha512-ihjs0E2SxvDgq/MK418hX6YycQgKhsqxpbZuZbHo0yKfqDWdymWMjWYIpCIzqDDLLKClHlXev8whW/8WXmJ0BA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "4.1.2",
|
||||
"rxjs": "7.8.2",
|
||||
"shell-quote": "1.8.3",
|
||||
"shell-quote": "1.8.4",
|
||||
"supports-color": "8.1.1",
|
||||
"tree-kill": "1.2.2",
|
||||
"yargs": "17.7.2"
|
||||
@@ -2970,6 +3039,21 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/copy-anything": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz",
|
||||
"integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-what": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
@@ -3571,6 +3655,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hookable": {
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
|
||||
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
@@ -3712,6 +3802,18 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-what": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz",
|
||||
"integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
@@ -3768,6 +3870,28 @@
|
||||
"integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/laravel-echo": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-2.3.7.tgz",
|
||||
"integrity": "sha512-6NoPtOk16PuaykVgcV1MV5665VPtrbyvacBD6AJ8NJdRjTwrOwKrgOYHgq4bz5E1zUbbVi2UJfMN7P7D/yceyQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pusher-js": "*",
|
||||
"socket.io-client": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"pusher-js": {
|
||||
"optional": true
|
||||
},
|
||||
"socket.io-client": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/laravel-precognition": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/laravel-precognition/-/laravel-precognition-1.0.2.tgz",
|
||||
@@ -4258,6 +4382,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mitt": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
||||
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
@@ -4423,6 +4553,12 @@
|
||||
"pbf": "bin/pbf"
|
||||
}
|
||||
},
|
||||
"node_modules/perfect-debounce": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
||||
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -4452,6 +4588,27 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pinia": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
|
||||
"integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^7.7.7"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.5.0",
|
||||
"vue": "^3.5.11"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pirates": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
|
||||
@@ -4663,6 +4820,16 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/pusher-js": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.5.0.tgz",
|
||||
"integrity": "sha512-V7uzGi9bqOOOyM/6IkJdpFyjGZj7llz1v0oWnYkZKcYLvbz6VcHVLmzKqkvegjuMumpfIEKGLmWHwFb39XFCpw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tweetnacl": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.15.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
|
||||
@@ -4861,6 +5028,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
|
||||
@@ -5342,9 +5515,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
|
||||
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz",
|
||||
"integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -5469,6 +5642,15 @@
|
||||
"source-map": "^0.5.6"
|
||||
}
|
||||
},
|
||||
"node_modules/speakingurl": {
|
||||
"version": "14.0.1",
|
||||
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
|
||||
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
@@ -5520,6 +5702,18 @@
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/superjson": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz",
|
||||
"integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"copy-anything": "^4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
@@ -5767,6 +5961,13 @@
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"dev": true,
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
|
||||
+6
-1
@@ -5,10 +5,12 @@
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"dev": "vite",
|
||||
"dev:all": "concurrently -s all \"php artisan serve\" \"php artisan reverb:start\" \"php artisan queue:work\" \"npm run dev\" > /dev/null 2>&1",
|
||||
"updateVersion": "cross-var docker build -t dredgy/flights-api:$npm_config_tag -t dredgy/flights-api:latest . && cross-var docker push dredgy/flights-api:$npm_config_tag && docker push dredgy/flights-api:latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@inertiajs/vue3": "^2.0.0",
|
||||
"@laravel/echo-vue": "^2.3.7",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@types/geojson": "^7946.0.16",
|
||||
@@ -17,10 +19,12 @@
|
||||
"@vitejs/plugin-vue": "^6.0.0",
|
||||
"autoprefixer": "^10.4.12",
|
||||
"axios": "^1.11.0",
|
||||
"concurrently": "^9.0.1",
|
||||
"concurrently": "^9.2.3",
|
||||
"cross-var": "^1.1.0",
|
||||
"laravel-echo": "^2.3.7",
|
||||
"laravel-vite-plugin": "^3.0.0",
|
||||
"postcss": "^8.4.31",
|
||||
"pusher-js": "^8.5.0",
|
||||
"sass-embedded": "^1.100.0",
|
||||
"tailwindcss": "^3.2.1",
|
||||
"typescript": "^6.0.2",
|
||||
@@ -35,6 +39,7 @@
|
||||
"echarts": "^6.0.0",
|
||||
"flag-icons": "^7.5.0",
|
||||
"maplibre-gl": "^5.22.0",
|
||||
"pinia": "^3.0.4",
|
||||
"vue-echarts": "^8.0.1",
|
||||
"vue3-apexcharts": "^1.11.1",
|
||||
"vuetify": "^4.1.2"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
import { useNotificationStore } from '@/stores/notificationStore';
|
||||
import { Notification } from '@/Types/types';
|
||||
|
||||
const props = defineProps<{
|
||||
userId: number;
|
||||
}>();
|
||||
|
||||
interface NotificationPayload {
|
||||
notification: Notification;
|
||||
}
|
||||
|
||||
const store = useNotificationStore();
|
||||
let channel: ReturnType<typeof window.Echo.private> | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
channel = window.Echo.private(`App.Models.User.${props.userId}`)
|
||||
.listen('.notification.created', (e: NotificationPayload) => {
|
||||
store.push(e.notification);
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
channel?.stopListening('.notification.created');
|
||||
window.Echo.leave(`App.Models.User.${props.userId}`);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template></template>
|
||||
@@ -1,19 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import {ref, watch} from 'vue'
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import axios from "axios";
|
||||
import {Notification} from "@/Types/types";
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import {local} from "laravel-vite-plugin/fonts";
|
||||
import { Notification } from "@/Types/types";
|
||||
import { Link } from "@inertiajs/vue3";
|
||||
import { useNotificationStore } from '@/stores/notificationStore';
|
||||
|
||||
const props = defineProps<{
|
||||
unreadCount: number
|
||||
}>()
|
||||
|
||||
const localUnreadCount = ref(props.unreadCount)
|
||||
watch(() => props.unreadCount, (val) => {
|
||||
localUnreadCount.value = val
|
||||
})
|
||||
const store = useNotificationStore();
|
||||
|
||||
onMounted(() => {
|
||||
store.setInitialUnreadCount(props.unreadCount);
|
||||
});
|
||||
|
||||
const open = ref(false)
|
||||
const notifications = ref<Notification[]>([])
|
||||
@@ -27,15 +27,10 @@ const markAllRead = async (notifications: Notification[]) => {
|
||||
unread.forEach(n => n.read_at = new Date().toISOString())
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:unreadCount', value: number): void
|
||||
}>()
|
||||
|
||||
watch(open, async (isOpen) => {
|
||||
if (!isOpen) return
|
||||
|
||||
localUnreadCount.value = 0
|
||||
emit('update:unreadCount', 0)
|
||||
store.unreadCount = 0
|
||||
|
||||
if (notifications.value.length) return
|
||||
|
||||
@@ -50,7 +45,7 @@ watch(open, async (isOpen) => {
|
||||
<template>
|
||||
<div class="notif-wrapper">
|
||||
<v-btn icon variant="text" @click="open = !open" aria-label="Notifications">
|
||||
<v-badge :content="localUnreadCount" :model-value="localUnreadCount > 0" color="primary">
|
||||
<v-badge :content="store.unreadCount" :model-value="store.unreadCount > 0" color="primary">
|
||||
<v-icon>mdi-bell-outline</v-icon>
|
||||
</v-badge>
|
||||
</v-btn>
|
||||
|
||||
@@ -1,54 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import { router } from "@inertiajs/vue3";
|
||||
import { Notification } from "@/Types/types";
|
||||
import axios from "axios";
|
||||
import { useNotificationStore } from '@/stores/notificationStore';
|
||||
|
||||
const activeToasts = ref<Notification[]>([])
|
||||
const seenNotificationIds = ref<Set<number>>(new Set())
|
||||
const achievementSound = new Audio('/sounds/seatBelt.wav')
|
||||
|
||||
function handleNewNotifications(notifications: Notification[]) {
|
||||
if (!notifications?.length) return
|
||||
|
||||
const newToasts: Notification[] = []
|
||||
for (const n of notifications) {
|
||||
if (!seenNotificationIds.value.has(n.id)) {
|
||||
seenNotificationIds.value.add(n.id)
|
||||
newToasts.push(n)
|
||||
}
|
||||
}
|
||||
|
||||
if (!newToasts.length) return
|
||||
activeToasts.value.push(...newToasts)
|
||||
achievementSound.play().catch(() => {})
|
||||
}
|
||||
|
||||
async function dismissToast(notification: Notification) {
|
||||
activeToasts.value = activeToasts.value.filter(n => n.id !== notification.id)
|
||||
await axios.patch(`/notifications/${notification.id}/read`)
|
||||
}
|
||||
|
||||
router.on('success', (event) => {
|
||||
handleNewNotifications(event.detail.page.props.achievement_notifications as Notification[] ?? [])
|
||||
})
|
||||
|
||||
// Handle initial page load notifications
|
||||
import { usePage } from "@inertiajs/vue3";
|
||||
import { SharedProps } from "@/Types/types";
|
||||
const page = usePage<SharedProps>().props;
|
||||
watch(
|
||||
() => page.achievement_notifications,
|
||||
handleNewNotifications,
|
||||
{ immediate: true }
|
||||
)
|
||||
const store = useNotificationStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="toast-stack">
|
||||
<TransitionGroup name="toast">
|
||||
<v-card
|
||||
v-for="notification in activeToasts"
|
||||
v-for="notification in store.toasts"
|
||||
:key="notification.id"
|
||||
class="toast-card glass"
|
||||
rounded="lg"
|
||||
@@ -66,7 +26,7 @@ watch(
|
||||
variant="text"
|
||||
size="small"
|
||||
class="ml-auto"
|
||||
@click="dismissToast(notification)"
|
||||
@click="store.dismiss(notification)"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
@@ -4,11 +4,14 @@ import MainFooter from "@/Components/FlightsGoneBy/MainFooter.vue";
|
||||
import Radar from "@/Components/FlightsGoneBy/Radar.vue";
|
||||
import StatusNotifications from "@/Components/FlightsGoneBy/StatusNotifications.vue";
|
||||
import ToastNotifications from "@/Components/FlightsGoneBy/ToastNotifications.vue";
|
||||
import { router } from "@inertiajs/vue3";
|
||||
import {router, usePage} from "@inertiajs/vue3";
|
||||
import { ref } from "vue";
|
||||
|
||||
import NotificationListener from "@/Components/FlightsGoneBy/NotificationListener.vue";
|
||||
import {SharedProps} from "@/Types/types";
|
||||
const transitionKey = ref(0);
|
||||
|
||||
const page = usePage<SharedProps>().props
|
||||
|
||||
router.on('success', () => {
|
||||
transitionKey.value++;
|
||||
});
|
||||
@@ -25,6 +28,7 @@ router.on('success', () => {
|
||||
</Transition>
|
||||
<MainFooter :key="`footer-${transitionKey}`" />
|
||||
</div>
|
||||
<NotificationListener v-if="page.auth.user?.id" :user-id="page.auth.user?.id" />
|
||||
<StatusNotifications />
|
||||
<ToastNotifications />
|
||||
</Radar>
|
||||
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
import Echo from 'laravel-echo';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Echo: Echo<'reverb'>;
|
||||
Pusher: unknown;
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,15 @@ import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
||||
import { ZiggyVue } from '../../vendor/tightenco/ziggy';
|
||||
import { createApp, h, DefineComponent } from 'vue';
|
||||
import vuetify from './plugins/vuetify';
|
||||
import { configureEcho } from '@laravel/echo-vue';
|
||||
const pinia = createPinia();
|
||||
configureEcho({
|
||||
broadcaster: 'reverb',
|
||||
});
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import 'flag-icons/css/flag-icons.min.css'
|
||||
import VueApexCharts from 'vue3-apexcharts'
|
||||
import {createPinia} from "pinia";
|
||||
|
||||
|
||||
const appName = document.querySelector('meta[name="app-name"]')?.getAttribute('content') || 'Laravel';
|
||||
@@ -25,6 +31,7 @@ createInertiaApp({
|
||||
.use(plugin)
|
||||
.use(ZiggyVue)
|
||||
.use(vuetify)
|
||||
.use(pinia)
|
||||
.use(VueApexCharts)
|
||||
.mount(el);
|
||||
},
|
||||
|
||||
Vendored
+14
@@ -2,3 +2,17 @@ import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
import Echo from 'laravel-echo';
|
||||
import Pusher from 'pusher-js';
|
||||
|
||||
window.Pusher = Pusher;
|
||||
|
||||
window.Echo = new Echo({
|
||||
broadcaster: 'reverb',
|
||||
key: import.meta.env.VITE_REVERB_APP_KEY,
|
||||
wsHost: import.meta.env.VITE_REVERB_HOST,
|
||||
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
|
||||
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
|
||||
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
});
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import { Notification } from '@/Types/types';
|
||||
import axios from 'axios';
|
||||
|
||||
export const useNotificationStore = defineStore('notifications', () => {
|
||||
const toasts = ref<Notification[]>([]);
|
||||
const unreadCount = ref(0);
|
||||
const latestNotification = ref<Notification | null>(null);
|
||||
const achievementSound = new Audio('/sounds/seatBelt.wav');
|
||||
|
||||
function push(notification: Notification) {
|
||||
toasts.value.push(notification);
|
||||
latestNotification.value = notification;
|
||||
unreadCount.value++;
|
||||
|
||||
if (notification.is_achievement) {
|
||||
achievementSound.play().catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
async function dismiss(notification: Notification) {
|
||||
toasts.value = toasts.value.filter(n => n.id !== notification.id);
|
||||
await axios.patch(`/notifications/${notification.id}/read`);
|
||||
unreadCount.value = Math.max(0, unreadCount.value - 1);
|
||||
}
|
||||
|
||||
function setInitialUnreadCount(count: number) {
|
||||
unreadCount.value = count;
|
||||
}
|
||||
|
||||
return { toasts, unreadCount, latestNotification, push, dismiss, setInitialUnreadCount};
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Broadcast;
|
||||
|
||||
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
|
||||
return (int) $user->id === (int) $id;
|
||||
});
|
||||
+2
-1
@@ -4,5 +4,6 @@ use Illuminate\Foundation\Inspiring;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
Schedule::command('app:update-alliances')->dailyAt('09:00')->runInBackground();
|
||||
Schedule::command('app:update-departed-flights')->hourly()->runInBackground();
|
||||
Schedule::command('app:update-arrived-flights')->hourly()->runInBackground();
|
||||
Schedule::command('app:update-departed-flights')->everyMinute()->runInBackground();
|
||||
Schedule::command('app:flight-feed-update')->everyMinute()->runInBackground();
|
||||
|
||||
Reference in New Issue
Block a user