the browser-facing portion of osu!
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'master' into beatmap-tags

authored by

bakaneko and committed by
GitHub
185c3ea1 9b47267e

+1670 -1567
+1 -15
.env.example
··· 189 189 # ES_CLIENT_CONNECT_TIMEOUT=0.5 190 190 # ES_SEARCH_TIMEOUT=5s 191 191 192 - # TOURNAMENT_BANNER_CURRENT_ID= 193 - # Image path/url for tournament supporter banner. 194 - # Will be appended with country abbreviation and `.jpg`. `@2x` version is also required (prepended before `.jpg`). 195 - # Example: 196 - # prefix: https://assets.ppy.sh/tournament-banners/official/twc2018_ 197 - # image path: https://assets.ppy.sh/tournament-banners/official/twc2018_JP.jpg 198 - # image path @2x: https://assets.ppy.sh/tournament-banners/official/twc2018_JP@2x.jpg 199 - # TOURNAMENT_BANNER_CURRENT_PREFIX= 200 - 201 - # TOURNAMENT_BANNER_PREVIOUS_ID= 202 - # Same as `_CURRENT_PREFIX`. 203 - # TOURNAMENT_BANNER_PREVIOUS_PREFIX= 204 - # Winning country code 205 - # TOURNAMENT_BANNER_PREVIOUS_WINNER_ID= 206 - 207 192 # {prefix}{filename}.png with {filename} the achievement slug as stored in database. 208 193 # USER_ACHIEVEMENT_ICON_PREFIX=https://assets.ppy.sh/user-achievements/ 209 194 ··· 244 229 # USER_PROFILE_SCORES_NOTICE= 245 230 246 231 # MULTIPLAYER_MAX_ATTEMPTS_LIMIT=128 232 + # MULTIPLAYER_ROOM_CLOSE_GRACE_PERIOD_MINUTES=5 247 233 248 234 # NOTIFICATION_QUEUE=notification 249 235 # NOTIFICATION_REDIS_HOST=127.0.0.1
+11
.github/workflows/tests.yml
··· 137 137 key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }} 138 138 restore-keys: ${{ runner.os }}-composer- 139 139 140 + - name: Get current date 141 + id: current-date 142 + run: echo "today=$(date '+%Y%m%d')" >> "$GITHUB_OUTPUT" 143 + 144 + - name: Cache ip2asn 145 + uses: actions/cache@v4 146 + with: 147 + path: database/ip2asn/ 148 + key: ip2asn-${{ steps.current-date.outputs.today }} 149 + restore-keys: ip2asn- 150 + 140 151 - run: ./build.sh 141 152 142 153 - name: Setup indices
+1 -1
Dockerfile.development
··· 42 42 43 43 WORKDIR /app 44 44 45 - RUN groupadd osuweb && useradd -g osuweb osuweb 45 + RUN groupadd osuweb && useradd -g osuweb -d /app/.docker osuweb 46 46 47 47 ENTRYPOINT ["/app/docker/development/entrypoint.sh"] 48 48 CMD ["octane"]
+1
SETUP.md
··· 186 186 Docker images need to be occasionally updated to make sure they're running latest version of the packages. 187 187 188 188 ``` 189 + docker compose pull 189 190 docker compose build --no-cache 190 191 ``` 191 192
+1 -1
app/Http/Controllers/Chat/Channels/MessagesController.php
··· 96 96 'until:int', 97 97 ], ['null_missing' => true]); 98 98 99 - $limit = clamp($limit ?? 50, 1, 50); 99 + $limit = \Number::clamp($limit ?? 50, 1, 50); 100 100 $user = auth()->user(); 101 101 102 102 $channel = Channel::findOrFail($channelId);
+1 -1
app/Http/Controllers/ContestEntriesController.php
··· 89 89 90 90 foreach ($entry->contest->scoringCategories as $category) { 91 91 $score = $scoresByCategoryId[$category->getKey()]; 92 - $value = clamp($score['value'], 0, $category->max_value); 92 + $value = \Number::clamp($score['value'], 0, $category->max_value); 93 93 94 94 $vote->scores()->firstOrNew([ 95 95 'contest_judge_vote_id' => $vote->getKey(),
+7 -7
app/Http/Controllers/Forum/TopicsController.php
··· 624 624 { 625 625 $rawParams = request()->all(); 626 626 $params = get_params($rawParams, null, [ 627 - 'start', // either number or "unread" 627 + 'start', // either number or "unread" or "latest" 628 628 'end:int', 629 629 'n:int', 630 630 ··· 636 636 ], ['null_missing' => true]); 637 637 638 638 $params['skip_layout'] = $params['skip_layout'] ?? false; 639 - $params['limit'] = clamp($params['limit'] ?? Post::PER_PAGE, 1, 50); 639 + $params['limit'] = \Number::clamp($params['limit'] ?? Post::PER_PAGE, 1, 50); 640 640 641 641 if ($userCanModerate) { 642 642 $params['with_deleted'] ??= UserProfileCustomization::forUser($currentUser)['forum_posts_show_deleted']; ··· 647 647 $params['cursor'] = cursor_from_params($rawParams); 648 648 649 649 if (!is_array($params['cursor'])) { 650 - if ($params['start'] === 'unread') { 651 - $params['start'] = Post::lastUnreadByUser($topic, $currentUser); 652 - } else { 653 - $params['start'] = get_int($params['start']); 654 - } 650 + $params['start'] = match ($params['start']) { 651 + 'latest' => $topic->topic_last_post_id, 652 + 'unread' => Post::lastUnreadByUser($topic, $currentUser), 653 + default => get_int($params['start']), 654 + }; 655 655 656 656 if ($params['n'] !== null && $params['n'] > 0) { 657 657 $post = $topic->nthPost($params['n']) ?? $topic->posts()->last();
+2 -2
app/Http/Controllers/MatchesController.php
··· 63 63 public function index() 64 64 { 65 65 $params = request()->all(); 66 - $limit = clamp(get_int($params['limit'] ?? null) ?? 50, 1, 50); 66 + $limit = \Number::clamp(get_int($params['limit'] ?? null) ?? 50, 1, 50); 67 67 $cursorHelper = LegacyMatch::makeDbCursorHelper($params['sort'] ?? null); 68 68 69 69 [$matches, $hasMore] = LegacyMatch ··· 147 147 $match = $params['match']; 148 148 $after = $params['after'] ?? null; 149 149 $before = $params['before'] ?? null; 150 - $limit = clamp($params['limit'] ?? 100, 1, 101); 150 + $limit = \Number::clamp($params['limit'] ?? 100, 1, 101); 151 151 152 152 $events = $match->events() 153 153 ->with([
+1 -1
app/Http/Controllers/Multiplayer/Rooms/Playlist/ScoresController.php
··· 50 50 { 51 51 $playlist = PlaylistItem::where('room_id', $roomId)->findOrFail($playlistId); 52 52 $params = request()->all(); 53 - $limit = clamp(get_int($params['limit'] ?? null) ?? 50, 1, 50); 53 + $limit = \Number::clamp(get_int($params['limit'] ?? null) ?? 50, 1, 50); 54 54 $cursorHelper = PlaylistItemUserHighScore::makeDbCursorHelper($params['sort'] ?? null); 55 55 56 56 $highScoresQuery = $playlist
+30 -31
app/Http/Controllers/Multiplayer/RoomsController.php
··· 20 20 $this->middleware('require-scopes:public', ['only' => ['index', 'leaderboard', 'show']]); 21 21 } 22 22 23 + public function destroy($id) 24 + { 25 + Room::findOrFail($id)->endGame(\Auth::user()); 26 + 27 + return response(null, 204); 28 + } 29 + 23 30 /** 24 31 * Get Multiplayer Rooms 25 32 * ··· 111 118 112 119 $room->join(auth()->user()); 113 120 114 - return response([], 204); 121 + return $this->createJoinedRoomResponse($room); 115 122 } 116 123 117 124 public function leaderboard($roomId) 118 125 { 119 - $limit = clamp(get_int(request('limit')) ?? Model::PER_PAGE, 1, 50); 126 + $limit = \Number::clamp(get_int(request('limit')) ?? Model::PER_PAGE, 1, 50); 120 127 $room = Room::findOrFail($roomId); 121 128 122 129 // leaderboard currently requires auth so auth()->check() is not required. ··· 161 168 } 162 169 163 170 if (is_api_request()) { 164 - return json_item( 165 - $room 166 - ->load('host.country') 167 - ->load('playlist.beatmap.beatmapset') 168 - ->load('playlist.beatmap.baseMaxCombo'), 169 - 'Multiplayer\Room', 170 - [ 171 - 'current_user_score.playlist_item_attempts', 172 - 'host.country', 173 - 'playlist.beatmap.beatmapset', 174 - 'playlist.beatmap.checksum', 175 - 'playlist.beatmap.max_combo', 176 - 'recent_participants', 177 - ] 178 - ); 171 + return $this->createJoinedRoomResponse($room); 179 172 } 180 173 181 174 if ($room->category === 'daily_challenge') { ··· 210 203 try { 211 204 $room = (new Room())->startGame(auth()->user(), request()->all()); 212 205 213 - return json_item( 214 - $room 215 - ->load('host.country') 216 - ->load('playlist.beatmap.beatmapset') 217 - ->load('playlist.beatmap.baseMaxCombo'), 218 - 'Multiplayer\Room', 219 - [ 220 - 'host.country', 221 - 'playlist.beatmap.beatmapset', 222 - 'playlist.beatmap.checksum', 223 - 'playlist.beatmap.max_combo', 224 - 'recent_participants', 225 - ] 226 - ); 206 + return $this->createJoinedRoomResponse($room); 227 207 } catch (InvariantException $e) { 228 208 return error_popup($e->getMessage(), $e->getStatusCode()); 229 209 } 210 + } 211 + 212 + private function createJoinedRoomResponse($room) 213 + { 214 + return json_item( 215 + $room 216 + ->load('host.country') 217 + ->load('playlist.beatmap.beatmapset') 218 + ->load('playlist.beatmap.baseMaxCombo'), 219 + 'Multiplayer\Room', 220 + [ 221 + 'current_user_score.playlist_item_attempts', 222 + 'host.country', 223 + 'playlist.beatmap.beatmapset', 224 + 'playlist.beatmap.checksum', 225 + 'playlist.beatmap.max_combo', 226 + 'recent_participants', 227 + ] 228 + ); 230 229 } 231 230 }
+2 -2
app/Http/Controllers/RankingController.php
··· 212 212 213 213 $maxResults = $this->maxResults($modeInt, $stats); 214 214 $maxPages = ceil($maxResults / static::PAGE_SIZE); 215 - // TODO: less repeatedly getting params out of request. 216 - $page = clamp(get_int(request('cursor.page') ?? request('page')), 1, $maxPages); 215 + $params = get_params(\Request::all(), null, ['cursor.page:int', 'page:int']); 216 + $page = \Number::clamp($params['cursor']['page'] ?? $params['page'] ?? 1, 1, $maxPages); 217 217 218 218 $stats = $stats->limit(static::PAGE_SIZE) 219 219 ->offset(static::PAGE_SIZE * ($page - 1))
+9 -2
app/Http/Controllers/ScoresController.php
··· 11 11 use App\Models\Solo\Score as SoloScore; 12 12 use App\Transformers\ScoreTransformer; 13 13 use App\Transformers\UserCompactTransformer; 14 + use Illuminate\Auth\AuthenticationException; 14 15 15 16 class ScoresController extends Controller 16 17 { ··· 22 23 23 24 $this->middleware('auth', ['except' => [ 24 25 'show', 26 + 'download', 25 27 ]]); 26 28 27 29 $this->middleware('require-scopes:public'); ··· 42 44 43 45 public function download($rulesetOrSoloId, $id = null) 44 46 { 47 + $currentUser = \Auth::user(); 48 + if (!is_api_request() && $currentUser === null) { 49 + throw new AuthenticationException('User is not logged in.'); 50 + } 51 + 45 52 $shouldRedirect = !is_api_request() && !from_app_url(); 46 53 if ($id === null) { 47 54 if ($shouldRedirect) { ··· 68 75 abort(404); 69 76 } 70 77 71 - $currentUser = \Auth::user(); 72 78 if ( 73 - !$currentUser->isRestricted() 79 + $currentUser !== null 80 + && !$currentUser->isRestricted() 74 81 && $currentUser->getKey() !== $score->user_id 75 82 && ($currentUser->token()?->client->password_client ?? false) 76 83 ) {
+12
app/Http/Controllers/SessionsController.php
··· 5 5 6 6 namespace App\Http\Controllers; 7 7 8 + use App\Libraries\User\CountryChange; 8 9 use App\Libraries\User\DatadogLoginAttempt; 9 10 use App\Libraries\User\ForceReactivation; 11 + use App\Models\Country; 10 12 use App\Models\User; 11 13 use App\Transformers\CurrentUserTransformer; 12 14 use Auth; ··· 86 88 ]); 87 89 88 90 return ujs_redirect(route('password-reset')); 91 + } 92 + 93 + // try fixing user country if it's currently set to unknown 94 + if ($user->country_acronym === Country::UNKNOWN) { 95 + try { 96 + CountryChange::handle($user, request_country(), 'automated unknown country fixup on login'); 97 + } catch (\Throwable $e) { 98 + // report failures but continue anyway 99 + log_error($e); 100 + } 89 101 } 90 102 91 103 DatadogLoginAttempt::log(null);
+1 -1
app/Http/Controllers/UserCoverPresetsController.php
··· 82 82 $item->update(['active' => $params['active']]); 83 83 } 84 84 85 - return ujs_redirect(route('user-cover-presets.index').'#cover-'.$item->getKey()); 85 + return response(null, 204); 86 86 } 87 87 }
+7 -5
app/Http/Controllers/UsersController.php
··· 17 17 use App\Libraries\UserRegistration; 18 18 use App\Models\Beatmap; 19 19 use App\Models\BeatmapDiscussion; 20 - use App\Models\Country; 21 20 use App\Models\IpBan; 22 21 use App\Models\Log; 23 22 use App\Models\User; ··· 729 728 730 729 private function sanitizedLimitParam() 731 730 { 732 - return clamp(get_int(request('limit')) ?? 5, 1, 100); 731 + return \Number::clamp(get_int(request('limit')) ?? 5, 1, 100); 733 732 } 734 733 735 734 private function getExtra($page, array $options, int $perPage = 10, int $offset = 0) ··· 983 982 'username', 984 983 ], ['null_missing' => true]); 985 984 $countryCode = request_country(); 986 - $country = Country::find($countryCode); 987 985 $params['user_ip'] = $ip; 988 - $params['country_acronym'] = $country === null ? '' : $country->getKey(); 986 + $params['country_acronym'] = $countryCode; 989 987 $params['user_lang'] = \App::getLocale(); 990 988 991 989 $registration = new UserRegistration($params); ··· 1009 1007 $user = $registration->user(); 1010 1008 1011 1009 // report unknown country code but ignore non-country from cloudflare 1012 - if ($countryCode !== null && $country === null && $countryCode !== 'T1') { 1010 + if ( 1011 + $countryCode !== null 1012 + && $countryCode !== 'T1' 1013 + && app('countries')->byCode($countryCode) === null 1014 + ) { 1013 1015 app('sentry')->getClient()->captureMessage( 1014 1016 'User registered from unknown country', 1015 1017 null,
-1
app/Http/Kernel.php
··· 37 37 Middleware\UpdateUserInfo::class, 38 38 Middleware\VerifyUserAlways::class, 39 39 Middleware\CheckUserBanStatus::class, 40 - Middleware\TurbolinksSupport::class, 41 40 ], 42 41 'lio' => [ 43 42 Middleware\LegacyInterOpAuth::class,
-35
app/Http/Middleware/TurbolinksSupport.php
··· 1 - <?php 2 - 3 - // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4 - // See the LICENCE file in the repository root for full licence text. 5 - 6 - namespace App\Http\Middleware; 7 - 8 - use Closure; 9 - 10 - class TurbolinksSupport 11 - { 12 - /** 13 - * Add turbolinks-redirect header if previous request 14 - * was a redirect. 15 - * 16 - * @param \Illuminate\Http\Request $request 17 - * @param \Closure $next 18 - * @return mixed 19 - */ 20 - public function handle($request, Closure $next) 21 - { 22 - $turbolinksLocation = $request->session()->pull('_turbolinks_location'); 23 - 24 - $response = $next($request); 25 - 26 - // symphony responder (debug error page) doesn't have header method 27 - $isNormalResponse = method_exists($response, 'header'); 28 - 29 - if ($isNormalResponse && present($turbolinksLocation)) { 30 - return $response->header('Turbolinks-Location', $turbolinksLocation); 31 - } else { 32 - return $response; 33 - } 34 - } 35 - }
+1 -1
app/Libraries/BBCodeFromDB.php
··· 325 325 { 326 326 $text = preg_replace_callback( 327 327 "#\[size=(\d+):{$this->uid}\]#", 328 - fn ($m) => '<span style="font-size:'.clamp((int) $m[1], 30, 200).'%;">', 328 + fn ($m) => '<span style="font-size:'.\Number::clamp((int) $m[1], 30, 200).'%;">', 329 329 $text, 330 330 ); 331 331 $text = strtr($text, ["[/size:{$this->uid}]" => '</span>']);
+1 -1
app/Libraries/CommentBundleParams.php
··· 53 53 } 54 54 55 55 if (array_key_exists('limit', $params)) { 56 - $this->limit = clamp(get_int($params['limit']), 1, 100); 56 + $this->limit = \Number::clamp(get_int($params['limit']) ?? 50, 1, 100); 57 57 } 58 58 59 59 if (array_key_exists('page', $params)) {
+1 -1
app/Libraries/Score/BeatmapScores.php
··· 19 19 20 20 public function __construct(private array $rawParams) 21 21 { 22 - $rawParams['limit'] = clamp($rawParams['limit'] ?? 50, 1, $GLOBALS['cfg']['osu']['beatmaps']['max_scores']); 22 + $rawParams['limit'] = \Number::clamp($rawParams['limit'] ?? 50, 1, $GLOBALS['cfg']['osu']['beatmaps']['max_scores']); 23 23 $rawParams['sort'] ??= 'score_desc'; 24 24 $this->baseParams = ScoreSearchParams::fromArray($rawParams); 25 25 }
+1 -2
app/Libraries/User/CountryChange.php
··· 9 9 10 10 use App\Exceptions\InvariantException; 11 11 use App\Models\Beatmap; 12 - use App\Models\Country; 13 12 use App\Models\User; 14 13 use App\Models\UserAccountHistory; 15 14 ··· 18 17 public static function handle(User $user, string $newCountry, string $reason): void 19 18 { 20 19 // Assert valid country acronym 21 - $country = Country::find($newCountry); 20 + $country = app('countries')->byCode($newCountry); 22 21 if ($country === null) { 23 22 throw new InvariantException('invalid country specified'); 24 23 }
+1 -1
app/Models/Beatmap.php
··· 371 371 } elseif ($percentSliderOrSpinner > 0.6) { 372 372 return $accuracy > 4 ? 5 : 4; 373 373 } else { 374 - return clamp($accuracy + 1, 4, 7); 374 + return \Number::clamp($accuracy + 1, 4, 7); 375 375 } 376 376 } else { 377 377 return max(1, $roundedValue);
+2
app/Models/Chat/Message.php
··· 9 9 use App\Models\Traits\ReportableInterface; 10 10 use App\Models\User; 11 11 use Carbon\Carbon; 12 + use Carbon\CarbonImmutable; 12 13 use Illuminate\Support\Collection; 13 14 14 15 /** ··· 92 93 ::where('message_id', '<=', $this->getKey()) 93 94 ->whereHas('channel', fn ($ch) => $ch->where('type', '<>', Channel::TYPES['pm'])) 94 95 ->where('user_id', $this->user_id) 96 + ->where('timestamp', '>', CarbonImmutable::now()->subDays(1)) 95 97 ->orderBy('timestamp', 'DESC') 96 98 ->with('channel') 97 99 ->limit(5)
+5 -1
app/Models/LegacyMatch/Score.php
··· 72 72 73 73 public function getRankAttribute($value): string 74 74 { 75 - return $value === '0' ? 'F' : $value; 75 + if ($value === '0') { 76 + $this->recalculateRank(); 77 + } 78 + 79 + return $this->attributes['rank']; 76 80 } 77 81 78 82 public function getScoringType()
+1 -1
app/Models/Model.php
··· 37 37 38 38 protected static function searchQueryAndParams(array $params) 39 39 { 40 - $limit = clamp(get_int($params['limit'] ?? null) ?? static::PER_PAGE, 5, 50); 40 + $limit = \Number::clamp(get_int($params['limit'] ?? null) ?? static::PER_PAGE, 5, 50); 41 41 $page = max(get_int($params['page'] ?? null), 1); 42 42 43 43 $offset = max_offset($page, $limit);
+24 -3
app/Models/Multiplayer/Room.php
··· 27 27 28 28 /** 29 29 * @property string $category 30 + * @property string $status 30 31 * @property Channel $channel 31 32 * @property int|null $channel_id 32 33 * @property \Carbon\Carbon|null $created_at ··· 200 201 $cursorHelper = static::makeDbCursorHelper($sort); 201 202 $query->cursorSort($cursorHelper, cursor_from_params($rawParams)); 202 203 203 - $limit = clamp($params['limit'] ?? $maxLimit, 1, $maxLimit); 204 + $limit = \Number::clamp($params['limit'] ?? $maxLimit, 1, $maxLimit); 204 205 $query->limit($limit); 205 206 206 207 return [ ··· 419 420 420 421 public function completePlay(ScoreToken $scoreToken, array $params): ScoreLink 421 422 { 422 - priv_check_user($scoreToken->user, 'MultiplayerScoreSubmit')->ensureCan(); 423 + priv_check_user($scoreToken->user, 'MultiplayerScoreSubmit', $this)->ensureCan(); 423 424 424 425 $this->assertValidCompletePlay(); 425 426 ··· 622 623 return $this->fresh(); 623 624 } 624 625 626 + /** 627 + * @throws InvariantException 628 + */ 629 + public function endGame(User $requestingUser) 630 + { 631 + priv_check_user($requestingUser, 'MultiplayerRoomDestroy', $this)->ensureCan(); 632 + 633 + if ($this->isRealtime()) { 634 + throw new InvariantException('Realtime rooms cannot be closed.'); 635 + } 636 + 637 + $gracePeriodMinutes = $GLOBALS['cfg']['osu']['multiplayer']['room_close_grace_period_minutes']; 638 + if ($this->starts_at->addMinutes($gracePeriodMinutes)->isPast()) { 639 + throw new InvariantException('The grace period for closing this room has expired.'); 640 + } 641 + 642 + $this->ends_at = now(); 643 + $this->save(); 644 + } 645 + 625 646 public function startPlay(User $user, PlaylistItem $playlistItem, int $buildId) 626 647 { 627 - priv_check_user($user, 'MultiplayerScoreSubmit')->ensureCan(); 648 + priv_check_user($user, 'MultiplayerScoreSubmit', $this)->ensureCan(); 628 649 629 650 $this->assertValidStartPlay($user, $playlistItem); 630 651
+2 -2
app/Models/NewsPost.php
··· 70 70 { 71 71 $query = static::published(); 72 72 73 - $limit = clamp(get_int($params['limit'] ?? null) ?? 20, 1, 21); 73 + $limit = \Number::clamp(get_int($params['limit'] ?? null) ?? 20, 1, 21); 74 74 75 75 $cursorHelper = static::makeDbCursorHelper(); 76 76 $cursor = cursor_from_params($params); ··· 255 255 return; 256 256 } 257 257 258 - if ($absolute && !starts_with($url, ['https://', 'http://'])) { 258 + if ($absolute && !is_http($url)) { 259 259 if ($url[0] === '/') { 260 260 $url = $GLOBALS['cfg']['app']['url'].$url; 261 261 } else {
+16 -55
app/Models/ProfileBanner.php
··· 6 6 namespace App\Models; 7 7 8 8 use Illuminate\Database\Eloquent\Builder; 9 + use Illuminate\Database\Eloquent\Relations\BelongsTo; 9 10 10 11 /** 11 12 * @property int $banner_id ··· 20 21 { 21 22 protected $table = 'osu_profile_banners'; 22 23 protected $primaryKey = 'banner_id'; 23 - protected array $macros = ['active']; 24 24 public $timestamps = false; 25 25 26 26 public function user() ··· 33 33 return $this->belongsTo(Tournament::class, 'tournament_id'); 34 34 } 35 35 36 - public function country() 36 + public function tournamentBanner(): BelongsTo 37 37 { 38 - return $this->belongsTo(Country::class, 'country_acronym'); 38 + return $this->belongsTo(TournamentBanner::class, 'tournament_id'); 39 39 } 40 40 41 - public function macroActive(): \Closure 41 + public function country() 42 42 { 43 - return function ($query) { 44 - $last = $query->orderBy('banner_id', 'DESC')->first(); 45 - 46 - if ($last !== null && $last->isActive()) { 47 - return $last; 48 - } 49 - }; 43 + return $this->belongsTo(Country::class, 'country_acronym'); 50 44 } 51 45 52 - public function scopeActiveOnly(Builder $query): Builder 46 + public function scopeActive(Builder $query): void 53 47 { 54 - $currentTournamentId = $GLOBALS['cfg']['osu']['tournament_banner']['current']['id']; 55 - if ($currentTournamentId !== null) { 56 - $mayHaveTournamentBanner = true; 57 - $query->where('tournament_id', $currentTournamentId); 58 - } 59 - $previousTournamentId = $GLOBALS['cfg']['osu']['tournament_banner']['previous']['id']; 60 - if ($previousTournamentId !== null) { 61 - $mayHaveTournamentBanner = true; 62 - $query->orWhere(fn ($q) => $q->where([ 63 - 'tournament_id' => $previousTournamentId, 64 - 'country_acronym' => $GLOBALS['cfg']['osu']['tournament_banner']['previous']['winner_id'], 65 - ])); 66 - } 67 - 68 - return $mayHaveTournamentBanner ?? false 69 - ? $query 70 - : $query->none(); 48 + $query->whereHas('tournamentBanner', fn ($q) => $q 49 + ->where('is_active', true) 50 + ->where(fn ($countryQuery) => $countryQuery 51 + ->whereNull('winner_country_acronym') 52 + ->orWhereColumn( 53 + $countryQuery->qualifyColumn('winner_country_acronym'), 54 + $query->qualifyColumn('country_acronym'), 55 + ))); 71 56 } 72 57 73 - public function image() 58 + public function image(): string 74 59 { 75 - $period = $this->period(); 76 - 77 - if ($period !== null) { 78 - $prefix = $GLOBALS['cfg']['osu']['tournament_banner'][$period]['prefix']; 79 - 80 - return "{$prefix}{$this->country_acronym}.jpg"; 81 - } 82 - } 83 - 84 - public function isActive() 85 - { 86 - $period = $this->period(); 87 - 88 - return $period === 'current' || 89 - ($period === 'previous' && $this->country_acronym === $GLOBALS['cfg']['osu']['tournament_banner']['previous']['winner_id']); 90 - } 91 - 92 - public function period() 93 - { 94 - switch ($this->tournament_id) { 95 - case $GLOBALS['cfg']['osu']['tournament_banner']['current']['id']: 96 - return 'current'; 97 - case $GLOBALS['cfg']['osu']['tournament_banner']['previous']['id']: 98 - return 'previous'; 99 - } 60 + return "{$this->tournamentBanner->banner_url_prefix}{$this->country_acronym}.jpg"; 100 61 } 101 62 }
+1 -1
app/Models/Score/Best/Model.php
··· 111 111 public function macroForListing(): \Closure 112 112 { 113 113 return function ($query, $limit) { 114 - $limit = clamp($limit ?? 50, 1, $GLOBALS['cfg']['osu']['beatmaps']['max_scores']); 114 + $limit = \Number::clamp($limit ?? 50, 1, $GLOBALS['cfg']['osu']['beatmaps']['max_scores']); 115 115 $newQuery = (clone $query)->with('user')->limit($limit + 100); 116 116 117 117 $result = [];
+25
app/Models/TournamentBanner.php
··· 1 + <?php 2 + 3 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4 + // See the LICENCE file in the repository root for full licence text. 5 + 6 + declare(strict_types=1); 7 + 8 + namespace App\Models; 9 + 10 + use Illuminate\Database\Eloquent\Relations\BelongsTo; 11 + 12 + class TournamentBanner extends Model 13 + { 14 + public $incrementing = false; 15 + 16 + protected $casts = [ 17 + 'is_active' => 'boolean', 18 + ]; 19 + protected $primaryKey = 'tournament_id'; 20 + 21 + public function tournament(): BelongsTo 22 + { 23 + return $this->belongsTo(Tournament::class, 'tournament_id'); 24 + } 25 + }
+1 -1
app/Models/Traits/Scoreable.php
··· 74 74 75 75 public function recalculateRank(): void 76 76 { 77 - if (!$this->passed) { 77 + if (!$this->pass) { 78 78 $this->rank = 'F'; 79 79 80 80 return;
+19 -20
app/Models/User.php
··· 707 707 708 708 // FIXME: this can probably be removed after old site is deactivated 709 709 // as there's same check in getter function. 710 - if (present($value) && !starts_with($value, ['http://', 'https://'])) { 710 + if (present($value) && !is_http($value)) { 711 711 $value = "https://{$value}"; 712 712 } 713 713 ··· 914 914 'orders', 915 915 'pivot', // laravel built-in relation when using belongsToMany 916 916 'profileBanners', 917 + 'profileBannersActive', 917 918 'profileBeatmapsetsGraveyard', 918 919 'profileBeatmapsetsLoved', 919 920 'profileBeatmapsetsPending', ··· 1308 1309 public function profileBanners() 1309 1310 { 1310 1311 return $this->hasMany(ProfileBanner::class); 1312 + } 1313 + 1314 + public function profileBannersActive(): HasMany 1315 + { 1316 + return $this->profileBanners()->active()->with('tournamentBanner')->orderBy('banner_id'); 1311 1317 } 1312 1318 1313 1319 public function storeAddresses() ··· 2312 2318 $this->isValidEmail(); 2313 2319 } 2314 2320 2315 - if ($this->isDirty('country_acronym')) { 2316 - if (present($this->country_acronym)) { 2317 - if (($country = Country::find($this->country_acronym)) !== null) { 2318 - // ensure matching case 2319 - $this->country_acronym = $country->getKey(); 2320 - } else { 2321 - $this->validationErrors()->add('country', '.invalid_country'); 2322 - } 2323 - } else { 2324 - $this->country_acronym = Country::UNKNOWN; 2321 + $countryAcronym = $this->country_acronym; 2322 + if ($countryAcronym === null) { 2323 + $this->country_acronym = Country::UNKNOWN; 2324 + } elseif ($this->isDirty('country_acronym') && $countryAcronym !== Country::UNKNOWN) { 2325 + if (app('countries')->byCode($countryAcronym) === null) { 2326 + $this->validationErrors()->add('country', '.invalid_country'); 2325 2327 } 2326 2328 } 2327 2329 ··· 2466 2468 { 2467 2469 $value = presence(trim($this->getRawAttribute('user_website'))); 2468 2470 2469 - if ($value === null) { 2470 - return null; 2471 - } 2472 - 2473 - if (starts_with($value, ['http://', 'https://'])) { 2474 - return $value; 2475 - } 2476 - 2477 - return "https://{$value}"; 2471 + return $value === null 2472 + ? null 2473 + : (is_http($value) 2474 + ? $value 2475 + : "https://{$value}" 2476 + ); 2478 2477 } 2479 2478 }
+2 -1
app/Models/UserAccountHistory.php
··· 84 84 public function scopeRecent($query) 85 85 { 86 86 return $query 87 - ->where('timestamp', '>', Carbon::now()->subDays($GLOBALS['cfg']['osu']['user']['ban_persist_days'])) 87 + ->whereRaw('(UNIX_TIMESTAMP(`timestamp`) + `period`) > ?', time()) 88 + ->orWhere('timestamp', '>', Carbon::now()->subDays($GLOBALS['cfg']['osu']['user']['ban_persist_days'])) 88 89 ->orWhere('permanent', true) 89 90 ->orderBy('timestamp', 'desc'); 90 91 }
+33 -20
app/Singletons/OsuAuthorize.php
··· 976 976 { 977 977 $prefix = 'chat.'; 978 978 979 + $this->ensureLoggedIn($user); 979 980 $this->ensureSessionVerified($user); 980 981 $this->ensureCleanRecord($user, $prefix); 981 982 // This check becomes useless when min_plays_allow_verified_bypass is enabled. ··· 1836 1837 1837 1838 /** 1838 1839 * @param User|null $user 1840 + * @param Room $room 1839 1841 * @return string 1840 1842 * @throws AuthorizationCheckException 1841 1843 */ 1842 - public function checkMultiplayerScoreSubmit(?User $user): string 1844 + public function checkMultiplayerRoomDestroy(?User $user, Room $room): string 1843 1845 { 1846 + $prefix = 'room.destroy.'; 1847 + 1844 1848 $this->ensureLoggedIn($user); 1845 1849 $this->ensureCleanRecord($user); 1850 + 1851 + if ($room->user_id !== $user->getKey()) { 1852 + return $prefix.'not_owner'; 1853 + } 1854 + 1855 + return 'ok'; 1856 + } 1857 + 1858 + /** 1859 + * @param User|null $user 1860 + * @return string 1861 + * @throws AuthorizationCheckException 1862 + */ 1863 + public function checkMultiplayerScoreSubmit(?User $user, Room $room): string 1864 + { 1865 + $this->ensureLoggedIn($user); 1866 + 1867 + if ($room->isRealtime()) { 1868 + $this->ensureCleanRecord($user); 1869 + } else { 1870 + if ($user->isRestricted()) { 1871 + throw new AuthorizationCheckException('restricted'); 1872 + } 1873 + } 1846 1874 1847 1875 return 'ok'; 1848 1876 } ··· 2037 2065 } 2038 2066 2039 2067 /** 2040 - * @param User|null $user 2041 - * @param string $prefix 2042 2068 * @throws AuthorizationCheckException 2043 2069 */ 2044 2070 public function ensureLoggedIn(?User $user, string $prefix = ''): void ··· 2049 2075 } 2050 2076 2051 2077 /** 2052 - * @param User|null $user 2053 - * @param string $prefix 2054 - * @return string 2055 2078 * @throws AuthorizationCheckException 2056 2079 */ 2057 - public function ensureCleanRecord(?User $user, string $prefix = ''): string 2080 + private function ensureCleanRecord(User $user, string $prefix = ''): void 2058 2081 { 2059 - if ($user === null) { 2060 - return 'unauthorized'; 2061 - } 2062 - 2063 2082 if ($user->isRestricted()) { 2064 2083 throw new AuthorizationCheckException($prefix.'restricted'); 2065 2084 } ··· 2067 2086 if ($user->isSilenced()) { 2068 2087 throw new AuthorizationCheckException($prefix.'silenced'); 2069 2088 } 2070 - 2071 - return 'ok'; 2072 2089 } 2073 2090 2074 2091 /** 2075 - * @param User|null $user 2076 2092 * @throws AuthorizationCheckException 2077 2093 */ 2078 - public function ensureHasPlayed(?User $user): void 2094 + private function ensureHasPlayed(User $user): void 2079 2095 { 2080 - if ($user === null || $user->isBot()) { 2096 + if ($user->isBot()) { 2081 2097 return; 2082 2098 } 2083 2099 ··· 2101 2117 /** 2102 2118 * Ensure User is logged in and verified. 2103 2119 * 2104 - * @param User|null $user 2105 2120 * @throws AuthorizationCheckException 2106 2121 */ 2107 - public function ensureSessionVerified(?User $user) 2122 + private function ensureSessionVerified(User $user) 2108 2123 { 2109 - $this->ensureLoggedIn($user); 2110 - 2111 2124 if (!$user->isSessionVerified()) { 2112 2125 throw new AuthorizationCheckException('require_verification'); 2113 2126 }
+1
app/Transformers/Multiplayer/RoomTransformer.php
··· 29 29 'id' => $room->id, 30 30 'name' => $room->name, 31 31 'category' => $room->category, 32 + 'status' => $room->status, 32 33 'type' => $room->type, 33 34 'user_id' => $room->user_id, 34 35 'starts_at' => json_time($room->starts_at),
+2 -2
app/Transformers/UserCompactTransformer.php
··· 159 159 160 160 public function includeActiveTournamentBanner(User $user) 161 161 { 162 - $banner = $user->profileBanners()->active(); 162 + $banner = $user->profileBannersActive->last(); 163 163 164 164 return $banner === null 165 165 ? $this->primitive(null) ··· 169 169 public function includeActiveTournamentBanners(User $user) 170 170 { 171 171 return $this->collection( 172 - $user->profileBanners()->activeOnly()->orderBy('banner_id')->get(), 172 + $user->profileBannersActive, 173 173 new ProfileBannerTransformer(), 174 174 ); 175 175 }
+22 -17
app/helpers.php
··· 835 835 'style' => user_color_style($colour, 'background-color'), 836 836 ]); 837 837 838 - $link = link_to_user($id, $username, null, []); 838 + $link = link_to_user($id, blade_safe($icon.e($username)), null, []); 839 839 if ($currentUserId === $id) { 840 840 $link = tag('strong', null, $link); 841 841 } 842 842 843 - return "{$icon} {$link}"; 843 + return $link; 844 844 } 845 845 846 846 function is_api_request(): bool 847 847 { 848 848 return str_starts_with(rawurldecode(Request::getPathInfo()), '/api/'); 849 + } 850 + 851 + function is_http(string $url): bool 852 + { 853 + return str_starts_with($url, 'http://') 854 + || str_starts_with($url, 'https://'); 849 855 } 850 856 851 857 function is_json_request(): bool ··· 935 941 936 942 function ujs_redirect($url, $status = 200) 937 943 { 938 - if (Request::ajax() && !Request::isMethod('get')) { 944 + $request = Request::instance(); 945 + // This is done mainly to work around fetch ignoring/removing anchor from page redirect. 946 + // Reference: https://github.com/hotwired/turbo/issues/211 947 + if ($request->headers->get('x-turbo-request-id') !== null) { 948 + if ($status === 200 && $request->getMethod() !== 'GET') { 949 + // Turbo doesn't like 200 response on non-GET requests. 950 + // Reference: https://github.com/hotwired/turbo/issues/22 951 + $status = 201; 952 + } 953 + 954 + return response($url, $status, ['content-type' => 'text/osu-turbo-redirect']); 955 + } elseif ($request->ajax() && $request->getMethod() !== 'GET') { 939 956 return ext_view('layout.ujs-redirect', compact('url'), 'js', $status); 940 957 } else { 941 - if (Request::header('Turbolinks-Referrer')) { 942 - Request::session()->put('_turbolinks_location', $url); 943 - } 944 - 945 958 // because non-3xx redirects make no sense. 946 959 if ($status < 300 || $status > 399) { 947 960 $status = 302; ··· 1100 1113 return ''; 1101 1114 } 1102 1115 1103 - $url = html_entity_decode_better($url); 1104 - 1105 1116 if ($GLOBALS['cfg']['osu']['camo']['key'] === null) { 1106 1117 return $url; 1107 1118 } 1108 1119 1109 - $isProxied = starts_with($url, $GLOBALS['cfg']['osu']['camo']['prefix']); 1120 + $isProxied = str_starts_with($url, $GLOBALS['cfg']['osu']['camo']['prefix']); 1110 1121 1111 1122 if ($isProxied) { 1112 1123 return $url; 1113 1124 } 1114 1125 1115 1126 // turn relative urls into absolute urls 1116 - if (!preg_match('/^https?\:\/\//', $url)) { 1127 + if (!is_http($url)) { 1117 1128 // ensure url is relative to the site root 1118 1129 if ($url[0] !== '/') { 1119 1130 $url = "/{$url}"; ··· 1795 1806 $match_pos = strpos($text, $split_on); 1796 1807 1797 1808 return $match_pos === false ? $text : substr($text, 0, $match_pos); 1798 - } 1799 - 1800 - // clamps $number to be between $min and $max 1801 - function clamp($number, $min, $max) 1802 - { 1803 - return min($max, max($min, $number)); 1804 1809 } 1805 1810 1806 1811 // e.g. 100634983048665 -> 100.63 trillion
+560 -641
composer.lock
··· 157 157 }, 158 158 { 159 159 "name": "brick/math", 160 - "version": "0.11.0", 160 + "version": "0.12.1", 161 161 "source": { 162 162 "type": "git", 163 163 "url": "https://github.com/brick/math.git", 164 - "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" 164 + "reference": "f510c0a40911935b77b86859eb5223d58d660df1" 165 165 }, 166 166 "dist": { 167 167 "type": "zip", 168 - "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", 169 - "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", 168 + "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1", 169 + "reference": "f510c0a40911935b77b86859eb5223d58d660df1", 170 170 "shasum": "" 171 171 }, 172 172 "require": { 173 - "php": "^8.0" 173 + "php": "^8.1" 174 174 }, 175 175 "require-dev": { 176 176 "php-coveralls/php-coveralls": "^2.2", 177 - "phpunit/phpunit": "^9.0", 178 - "vimeo/psalm": "5.0.0" 177 + "phpunit/phpunit": "^10.1", 178 + "vimeo/psalm": "5.16.0" 179 179 }, 180 180 "type": "library", 181 181 "autoload": { ··· 195 195 "arithmetic", 196 196 "bigdecimal", 197 197 "bignum", 198 + "bignumber", 198 199 "brick", 199 - "math" 200 + "decimal", 201 + "integer", 202 + "math", 203 + "mathematics", 204 + "rational" 200 205 ], 201 206 "support": { 202 207 "issues": "https://github.com/brick/math/issues", 203 - "source": "https://github.com/brick/math/tree/0.11.0" 208 + "source": "https://github.com/brick/math/tree/0.12.1" 204 209 }, 205 210 "funding": [ 206 211 { ··· 208 213 "type": "github" 209 214 } 210 215 ], 211 - "time": "2023-01-15T23:15:59+00:00" 216 + "time": "2023-11-29T23:19:16+00:00" 212 217 }, 213 218 { 214 219 "name": "carbonphp/carbon-doctrine-types", 215 - "version": "3.1.0", 220 + "version": "2.1.0", 216 221 "source": { 217 222 "type": "git", 218 223 "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", 219 - "reference": "a31d3358a2a5d6ae947df1691d1f321418a5f3d5" 224 + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb" 220 225 }, 221 226 "dist": { 222 227 "type": "zip", 223 - "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/a31d3358a2a5d6ae947df1691d1f321418a5f3d5", 224 - "reference": "a31d3358a2a5d6ae947df1691d1f321418a5f3d5", 228 + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", 229 + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", 225 230 "shasum": "" 226 231 }, 227 232 "require": { 228 - "php": "^8.1" 233 + "php": "^7.4 || ^8.0" 229 234 }, 230 235 "conflict": { 231 - "doctrine/dbal": "<4.0.0 || >=5.0.0" 236 + "doctrine/dbal": "<3.7.0 || >=4.0.0" 232 237 }, 233 238 "require-dev": { 234 - "doctrine/dbal": "^4.0.0", 239 + "doctrine/dbal": "^3.7.0", 235 240 "nesbot/carbon": "^2.71.0 || ^3.0.0", 236 241 "phpunit/phpunit": "^10.3" 237 242 }, ··· 261 266 ], 262 267 "support": { 263 268 "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", 264 - "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.1.0" 269 + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0" 265 270 }, 266 271 "funding": [ 267 272 { ··· 277 282 "type": "tidelift" 278 283 } 279 284 ], 280 - "time": "2023-12-10T15:33:53+00:00" 285 + "time": "2023-12-11T17:09:12+00:00" 281 286 }, 282 287 { 283 288 "name": "chaseconey/laravel-datadog-helper", ··· 548 553 }, 549 554 { 550 555 "name": "dflydev/dot-access-data", 551 - "version": "v3.0.2", 556 + "version": "v3.0.3", 552 557 "source": { 553 558 "type": "git", 554 559 "url": "https://github.com/dflydev/dflydev-dot-access-data.git", 555 - "reference": "f41715465d65213d644d3141a6a93081be5d3549" 560 + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" 556 561 }, 557 562 "dist": { 558 563 "type": "zip", 559 - "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/f41715465d65213d644d3141a6a93081be5d3549", 560 - "reference": "f41715465d65213d644d3141a6a93081be5d3549", 564 + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", 565 + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", 561 566 "shasum": "" 562 567 }, 563 568 "require": { ··· 617 622 ], 618 623 "support": { 619 624 "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", 620 - "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.2" 625 + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" 621 626 }, 622 - "time": "2022-10-27T11:44:00+00:00" 627 + "time": "2024-07-08T12:26:09+00:00" 623 628 }, 624 629 { 625 630 "name": "doctrine/inflector", 626 - "version": "2.0.8", 631 + "version": "2.0.10", 627 632 "source": { 628 633 "type": "git", 629 634 "url": "https://github.com/doctrine/inflector.git", 630 - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" 635 + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" 631 636 }, 632 637 "dist": { 633 638 "type": "zip", 634 - "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", 635 - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", 639 + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", 640 + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", 636 641 "shasum": "" 637 642 }, 638 643 "require": { ··· 694 699 ], 695 700 "support": { 696 701 "issues": "https://github.com/doctrine/inflector/issues", 697 - "source": "https://github.com/doctrine/inflector/tree/2.0.8" 702 + "source": "https://github.com/doctrine/inflector/tree/2.0.10" 698 703 }, 699 704 "funding": [ 700 705 { ··· 710 715 "type": "tidelift" 711 716 } 712 717 ], 713 - "time": "2023-06-16T13:40:37+00:00" 718 + "time": "2024-02-18T20:23:39+00:00" 714 719 }, 715 720 { 716 721 "name": "doctrine/lexer", 717 - "version": "3.0.0", 722 + "version": "3.0.1", 718 723 "source": { 719 724 "type": "git", 720 725 "url": "https://github.com/doctrine/lexer.git", 721 - "reference": "84a527db05647743d50373e0ec53a152f2cde568" 726 + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" 722 727 }, 723 728 "dist": { 724 729 "type": "zip", 725 - "url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568", 726 - "reference": "84a527db05647743d50373e0ec53a152f2cde568", 730 + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", 731 + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", 727 732 "shasum": "" 728 733 }, 729 734 "require": { 730 735 "php": "^8.1" 731 736 }, 732 737 "require-dev": { 733 - "doctrine/coding-standard": "^10", 734 - "phpstan/phpstan": "^1.9", 735 - "phpunit/phpunit": "^9.5", 738 + "doctrine/coding-standard": "^12", 739 + "phpstan/phpstan": "^1.10", 740 + "phpunit/phpunit": "^10.5", 736 741 "psalm/plugin-phpunit": "^0.18.3", 737 - "vimeo/psalm": "^5.0" 742 + "vimeo/psalm": "^5.21" 738 743 }, 739 744 "type": "library", 740 745 "autoload": { ··· 771 776 ], 772 777 "support": { 773 778 "issues": "https://github.com/doctrine/lexer/issues", 774 - "source": "https://github.com/doctrine/lexer/tree/3.0.0" 779 + "source": "https://github.com/doctrine/lexer/tree/3.0.1" 775 780 }, 776 781 "funding": [ 777 782 { ··· 787 792 "type": "tidelift" 788 793 } 789 794 ], 790 - "time": "2022-12-15T16:57:16+00:00" 795 + "time": "2024-02-05T11:56:58+00:00" 791 796 }, 792 797 { 793 798 "name": "dragonmantank/cron-expression", 794 - "version": "v3.3.2", 799 + "version": "v3.4.0", 795 800 "source": { 796 801 "type": "git", 797 802 "url": "https://github.com/dragonmantank/cron-expression.git", 798 - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8" 803 + "reference": "8c784d071debd117328803d86b2097615b457500" 799 804 }, 800 805 "dist": { 801 806 "type": "zip", 802 - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8", 803 - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8", 807 + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", 808 + "reference": "8c784d071debd117328803d86b2097615b457500", 804 809 "shasum": "" 805 810 }, 806 811 "require": { ··· 813 818 "require-dev": { 814 819 "phpstan/extension-installer": "^1.0", 815 820 "phpstan/phpstan": "^1.0", 816 - "phpstan/phpstan-webmozart-assert": "^1.0", 817 821 "phpunit/phpunit": "^7.0|^8.0|^9.0" 818 822 }, 819 823 "type": "library", 824 + "extra": { 825 + "branch-alias": { 826 + "dev-master": "3.x-dev" 827 + } 828 + }, 820 829 "autoload": { 821 830 "psr-4": { 822 831 "Cron\\": "src/Cron/" ··· 840 849 ], 841 850 "support": { 842 851 "issues": "https://github.com/dragonmantank/cron-expression/issues", 843 - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2" 852 + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" 844 853 }, 845 854 "funding": [ 846 855 { ··· 848 857 "type": "github" 849 858 } 850 859 ], 851 - "time": "2022-09-10T18:51:20+00:00" 860 + "time": "2024-10-09T13:47:03+00:00" 852 861 }, 853 862 { 854 863 "name": "egulias/email-validator", 855 - "version": "4.0.1", 864 + "version": "4.0.2", 856 865 "source": { 857 866 "type": "git", 858 867 "url": "https://github.com/egulias/EmailValidator.git", 859 - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff" 868 + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" 860 869 }, 861 870 "dist": { 862 871 "type": "zip", 863 - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/3a85486b709bc384dae8eb78fb2eec649bdb64ff", 864 - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff", 872 + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", 873 + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", 865 874 "shasum": "" 866 875 }, 867 876 "require": { ··· 870 879 "symfony/polyfill-intl-idn": "^1.26" 871 880 }, 872 881 "require-dev": { 873 - "phpunit/phpunit": "^9.5.27", 874 - "vimeo/psalm": "^4.30" 882 + "phpunit/phpunit": "^10.2", 883 + "vimeo/psalm": "^5.12" 875 884 }, 876 885 "suggest": { 877 886 "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" ··· 907 916 ], 908 917 "support": { 909 918 "issues": "https://github.com/egulias/EmailValidator/issues", 910 - "source": "https://github.com/egulias/EmailValidator/tree/4.0.1" 919 + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" 911 920 }, 912 921 "funding": [ 913 922 { ··· 915 924 "type": "github" 916 925 } 917 926 ], 918 - "time": "2023-01-14T14:17:03+00:00" 927 + "time": "2023-10-06T06:47:41+00:00" 919 928 }, 920 929 { 921 930 "name": "elasticsearch/elasticsearch", ··· 1405 1414 }, 1406 1415 { 1407 1416 "name": "fruitcake/php-cors", 1408 - "version": "v1.2.0", 1417 + "version": "v1.3.0", 1409 1418 "source": { 1410 1419 "type": "git", 1411 1420 "url": "https://github.com/fruitcake/php-cors.git", 1412 - "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e" 1421 + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" 1413 1422 }, 1414 1423 "dist": { 1415 1424 "type": "zip", 1416 - "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/58571acbaa5f9f462c9c77e911700ac66f446d4e", 1417 - "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e", 1425 + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", 1426 + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", 1418 1427 "shasum": "" 1419 1428 }, 1420 1429 "require": { 1421 1430 "php": "^7.4|^8.0", 1422 - "symfony/http-foundation": "^4.4|^5.4|^6" 1431 + "symfony/http-foundation": "^4.4|^5.4|^6|^7" 1423 1432 }, 1424 1433 "require-dev": { 1425 1434 "phpstan/phpstan": "^1.4", ··· 1429 1438 "type": "library", 1430 1439 "extra": { 1431 1440 "branch-alias": { 1432 - "dev-main": "1.1-dev" 1441 + "dev-master": "1.2-dev" 1433 1442 } 1434 1443 }, 1435 1444 "autoload": { ··· 1460 1469 ], 1461 1470 "support": { 1462 1471 "issues": "https://github.com/fruitcake/php-cors/issues", 1463 - "source": "https://github.com/fruitcake/php-cors/tree/v1.2.0" 1472 + "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" 1464 1473 }, 1465 1474 "funding": [ 1466 1475 { ··· 1472 1481 "type": "github" 1473 1482 } 1474 1483 ], 1475 - "time": "2022-02-20T15:07:15+00:00" 1484 + "time": "2023-10-12T05:21:21+00:00" 1476 1485 }, 1477 1486 { 1478 1487 "name": "graham-campbell/bounded-cache", ··· 1699 1708 }, 1700 1709 { 1701 1710 "name": "graham-campbell/result-type", 1702 - "version": "v1.1.1", 1711 + "version": "v1.1.3", 1703 1712 "source": { 1704 1713 "type": "git", 1705 1714 "url": "https://github.com/GrahamCampbell/Result-Type.git", 1706 - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831" 1715 + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" 1707 1716 }, 1708 1717 "dist": { 1709 1718 "type": "zip", 1710 - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", 1711 - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", 1719 + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", 1720 + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", 1712 1721 "shasum": "" 1713 1722 }, 1714 1723 "require": { 1715 1724 "php": "^7.2.5 || ^8.0", 1716 - "phpoption/phpoption": "^1.9.1" 1725 + "phpoption/phpoption": "^1.9.3" 1717 1726 }, 1718 1727 "require-dev": { 1719 - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" 1728 + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" 1720 1729 }, 1721 1730 "type": "library", 1722 1731 "autoload": { ··· 1745 1754 ], 1746 1755 "support": { 1747 1756 "issues": "https://github.com/GrahamCampbell/Result-Type/issues", 1748 - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1" 1757 + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" 1749 1758 }, 1750 1759 "funding": [ 1751 1760 { ··· 1757 1766 "type": "tidelift" 1758 1767 } 1759 1768 ], 1760 - "time": "2023-02-25T20:23:15+00:00" 1769 + "time": "2024-07-20T21:45:45+00:00" 1761 1770 }, 1762 1771 { 1763 1772 "name": "guzzlehttp/guzzle", ··· 2086 2095 }, 2087 2096 { 2088 2097 "name": "guzzlehttp/uri-template", 2089 - "version": "v1.0.1", 2098 + "version": "v1.0.3", 2090 2099 "source": { 2091 2100 "type": "git", 2092 2101 "url": "https://github.com/guzzle/uri-template.git", 2093 - "reference": "b945d74a55a25a949158444f09ec0d3c120d69e2" 2102 + "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c" 2094 2103 }, 2095 2104 "dist": { 2096 2105 "type": "zip", 2097 - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/b945d74a55a25a949158444f09ec0d3c120d69e2", 2098 - "reference": "b945d74a55a25a949158444f09ec0d3c120d69e2", 2106 + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/ecea8feef63bd4fef1f037ecb288386999ecc11c", 2107 + "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c", 2099 2108 "shasum": "" 2100 2109 }, 2101 2110 "require": { 2102 2111 "php": "^7.2.5 || ^8.0", 2103 - "symfony/polyfill-php80": "^1.17" 2112 + "symfony/polyfill-php80": "^1.24" 2104 2113 }, 2105 2114 "require-dev": { 2106 - "phpunit/phpunit": "^8.5.19 || ^9.5.8", 2115 + "bamarni/composer-bin-plugin": "^1.8.2", 2116 + "phpunit/phpunit": "^8.5.36 || ^9.6.15", 2107 2117 "uri-template/tests": "1.0.0" 2108 2118 }, 2109 2119 "type": "library", 2110 2120 "extra": { 2111 - "branch-alias": { 2112 - "dev-master": "1.0-dev" 2121 + "bamarni-bin": { 2122 + "bin-links": true, 2123 + "forward-command": false 2113 2124 } 2114 2125 }, 2115 2126 "autoload": { ··· 2150 2161 ], 2151 2162 "support": { 2152 2163 "issues": "https://github.com/guzzle/uri-template/issues", 2153 - "source": "https://github.com/guzzle/uri-template/tree/v1.0.1" 2164 + "source": "https://github.com/guzzle/uri-template/tree/v1.0.3" 2154 2165 }, 2155 2166 "funding": [ 2156 2167 { ··· 2166 2177 "type": "tidelift" 2167 2178 } 2168 2179 ], 2169 - "time": "2021-10-07T12:57:01+00:00" 2180 + "time": "2023-12-03T19:50:20+00:00" 2170 2181 }, 2171 2182 { 2172 2183 "name": "http-interop/http-factory-guzzle", ··· 2758 2769 }, 2759 2770 { 2760 2771 "name": "laravel/framework", 2761 - "version": "v10.28.0", 2772 + "version": "v10.48.23", 2762 2773 "source": { 2763 2774 "type": "git", 2764 2775 "url": "https://github.com/laravel/framework.git", 2765 - "reference": "09137f50f715c1efc649788a26092dcb1ec4ab6e" 2776 + "reference": "625269ca4881d2b50eded2045cb930960a181d98" 2766 2777 }, 2767 2778 "dist": { 2768 2779 "type": "zip", 2769 - "url": "https://api.github.com/repos/laravel/framework/zipball/09137f50f715c1efc649788a26092dcb1ec4ab6e", 2770 - "reference": "09137f50f715c1efc649788a26092dcb1ec4ab6e", 2780 + "url": "https://api.github.com/repos/laravel/framework/zipball/625269ca4881d2b50eded2045cb930960a181d98", 2781 + "reference": "625269ca4881d2b50eded2045cb930960a181d98", 2771 2782 "shasum": "" 2772 2783 }, 2773 2784 "require": { 2774 - "brick/math": "^0.9.3|^0.10.2|^0.11", 2785 + "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", 2775 2786 "composer-runtime-api": "^2.2", 2776 2787 "doctrine/inflector": "^2.0.5", 2777 2788 "dragonmantank/cron-expression": "^3.3.2", ··· 2800 2811 "symfony/console": "^6.2", 2801 2812 "symfony/error-handler": "^6.2", 2802 2813 "symfony/finder": "^6.2", 2803 - "symfony/http-foundation": "^6.2", 2814 + "symfony/http-foundation": "^6.4", 2804 2815 "symfony/http-kernel": "^6.2", 2805 2816 "symfony/mailer": "^6.2", 2806 2817 "symfony/mime": "^6.2", ··· 2813 2824 "voku/portable-ascii": "^2.0" 2814 2825 }, 2815 2826 "conflict": { 2827 + "carbonphp/carbon-doctrine-types": ">=3.0", 2828 + "doctrine/dbal": ">=4.0", 2829 + "mockery/mockery": "1.6.8", 2830 + "phpunit/phpunit": ">=11.0.0", 2816 2831 "tightenco/collect": "<5.5.33" 2817 2832 }, 2818 2833 "provide": { ··· 2867 2882 "league/flysystem-read-only": "^3.3", 2868 2883 "league/flysystem-sftp-v3": "^3.0", 2869 2884 "mockery/mockery": "^1.5.1", 2870 - "orchestra/testbench-core": "^8.12", 2885 + "nyholm/psr7": "^1.2", 2886 + "orchestra/testbench-core": "^8.23.4", 2871 2887 "pda/pheanstalk": "^4.0", 2872 2888 "phpstan/phpstan": "^1.4.7", 2873 2889 "phpunit/phpunit": "^10.0.7", 2874 2890 "predis/predis": "^2.0.2", 2875 2891 "symfony/cache": "^6.2", 2876 - "symfony/http-client": "^6.2.4" 2892 + "symfony/http-client": "^6.2.4", 2893 + "symfony/psr-http-message-bridge": "^2.0" 2877 2894 }, 2878 2895 "suggest": { 2879 2896 "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", ··· 2922 2939 "files": [ 2923 2940 "src/Illuminate/Collections/helpers.php", 2924 2941 "src/Illuminate/Events/functions.php", 2942 + "src/Illuminate/Filesystem/functions.php", 2925 2943 "src/Illuminate/Foundation/helpers.php", 2926 2944 "src/Illuminate/Support/helpers.php" 2927 2945 ], ··· 2954 2972 "issues": "https://github.com/laravel/framework/issues", 2955 2973 "source": "https://github.com/laravel/framework" 2956 2974 }, 2957 - "time": "2023-10-10T13:01:37+00:00" 2975 + "time": "2024-11-12T15:39:10+00:00" 2958 2976 }, 2959 2977 { 2960 2978 "name": "laravel/helpers", ··· 3180 3198 }, 3181 3199 { 3182 3200 "name": "laravel/prompts", 3183 - "version": "v0.1.11", 3201 + "version": "v0.1.25", 3184 3202 "source": { 3185 3203 "type": "git", 3186 3204 "url": "https://github.com/laravel/prompts.git", 3187 - "reference": "cce65a90e64712909ea1adc033e1d88de8455ffd" 3205 + "reference": "7b4029a84c37cb2725fc7f011586e2997040bc95" 3188 3206 }, 3189 3207 "dist": { 3190 3208 "type": "zip", 3191 - "url": "https://api.github.com/repos/laravel/prompts/zipball/cce65a90e64712909ea1adc033e1d88de8455ffd", 3192 - "reference": "cce65a90e64712909ea1adc033e1d88de8455ffd", 3209 + "url": "https://api.github.com/repos/laravel/prompts/zipball/7b4029a84c37cb2725fc7f011586e2997040bc95", 3210 + "reference": "7b4029a84c37cb2725fc7f011586e2997040bc95", 3193 3211 "shasum": "" 3194 3212 }, 3195 3213 "require": { 3196 3214 "ext-mbstring": "*", 3197 3215 "illuminate/collections": "^10.0|^11.0", 3198 3216 "php": "^8.1", 3199 - "symfony/console": "^6.2" 3217 + "symfony/console": "^6.2|^7.0" 3200 3218 }, 3201 3219 "conflict": { 3202 3220 "illuminate/console": ">=10.17.0 <10.25.0", ··· 3205 3223 "require-dev": { 3206 3224 "mockery/mockery": "^1.5", 3207 3225 "pestphp/pest": "^2.3", 3208 - "phpstan/phpstan": "^1.10", 3226 + "phpstan/phpstan": "^1.11", 3209 3227 "phpstan/phpstan-mockery": "^1.1" 3210 3228 }, 3211 3229 "suggest": { ··· 3229 3247 "license": [ 3230 3248 "MIT" 3231 3249 ], 3250 + "description": "Add beautiful and user-friendly forms to your command-line applications.", 3232 3251 "support": { 3233 3252 "issues": "https://github.com/laravel/prompts/issues", 3234 - "source": "https://github.com/laravel/prompts/tree/v0.1.11" 3253 + "source": "https://github.com/laravel/prompts/tree/v0.1.25" 3235 3254 }, 3236 - "time": "2023-10-03T01:07:35+00:00" 3255 + "time": "2024-08-12T22:06:33+00:00" 3237 3256 }, 3238 3257 { 3239 3258 "name": "laravel/serializable-closure", 3240 - "version": "v1.3.3", 3259 + "version": "v1.3.6", 3241 3260 "source": { 3242 3261 "type": "git", 3243 3262 "url": "https://github.com/laravel/serializable-closure.git", 3244 - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" 3263 + "reference": "f865a58ea3a0107c336b7045104c75243fa59d96" 3245 3264 }, 3246 3265 "dist": { 3247 3266 "type": "zip", 3248 - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", 3249 - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", 3267 + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f865a58ea3a0107c336b7045104c75243fa59d96", 3268 + "reference": "f865a58ea3a0107c336b7045104c75243fa59d96", 3250 3269 "shasum": "" 3251 3270 }, 3252 3271 "require": { 3253 3272 "php": "^7.3|^8.0" 3254 3273 }, 3255 3274 "require-dev": { 3256 - "nesbot/carbon": "^2.61", 3275 + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", 3276 + "nesbot/carbon": "^2.61|^3.0", 3257 3277 "pestphp/pest": "^1.21.3", 3258 3278 "phpstan/phpstan": "^1.8.2", 3259 - "symfony/var-dumper": "^5.4.11" 3279 + "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0" 3260 3280 }, 3261 3281 "type": "library", 3262 3282 "extra": { ··· 3293 3313 "issues": "https://github.com/laravel/serializable-closure/issues", 3294 3314 "source": "https://github.com/laravel/serializable-closure" 3295 3315 }, 3296 - "time": "2023-11-08T14:08:06+00:00" 3316 + "time": "2024-11-11T17:06:04+00:00" 3297 3317 }, 3298 3318 { 3299 3319 "name": "laravel/slack-notification-channel", ··· 3563 3583 }, 3564 3584 { 3565 3585 "name": "league/commonmark", 3566 - "version": "2.4.1", 3586 + "version": "2.5.3", 3567 3587 "source": { 3568 3588 "type": "git", 3569 3589 "url": "https://github.com/thephpleague/commonmark.git", 3570 - "reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5" 3590 + "reference": "b650144166dfa7703e62a22e493b853b58d874b0" 3571 3591 }, 3572 3592 "dist": { 3573 3593 "type": "zip", 3574 - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/3669d6d5f7a47a93c08ddff335e6d945481a1dd5", 3575 - "reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5", 3594 + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/b650144166dfa7703e62a22e493b853b58d874b0", 3595 + "reference": "b650144166dfa7703e62a22e493b853b58d874b0", 3576 3596 "shasum": "" 3577 3597 }, 3578 3598 "require": { ··· 3585 3605 }, 3586 3606 "require-dev": { 3587 3607 "cebe/markdown": "^1.0", 3588 - "commonmark/cmark": "0.30.0", 3589 - "commonmark/commonmark.js": "0.30.0", 3608 + "commonmark/cmark": "0.31.1", 3609 + "commonmark/commonmark.js": "0.31.1", 3590 3610 "composer/package-versions-deprecated": "^1.8", 3591 3611 "embed/embed": "^4.4", 3592 3612 "erusev/parsedown": "^1.0", ··· 3595 3615 "michelf/php-markdown": "^1.4 || ^2.0", 3596 3616 "nyholm/psr7": "^1.5", 3597 3617 "phpstan/phpstan": "^1.8.2", 3598 - "phpunit/phpunit": "^9.5.21", 3618 + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", 3599 3619 "scrutinizer/ocular": "^1.8.1", 3600 - "symfony/finder": "^5.3 | ^6.0", 3601 - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0", 3620 + "symfony/finder": "^5.3 | ^6.0 || ^7.0", 3621 + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 || ^7.0", 3602 3622 "unleashedtech/php-coding-standard": "^3.1.1", 3603 3623 "vimeo/psalm": "^4.24.0 || ^5.0.0" 3604 3624 }, ··· 3608 3628 "type": "library", 3609 3629 "extra": { 3610 3630 "branch-alias": { 3611 - "dev-main": "2.5-dev" 3631 + "dev-main": "2.6-dev" 3612 3632 } 3613 3633 }, 3614 3634 "autoload": { ··· 3665 3685 "type": "tidelift" 3666 3686 } 3667 3687 ], 3668 - "time": "2023-08-30T16:55:00+00:00" 3688 + "time": "2024-08-16T11:46:16+00:00" 3669 3689 }, 3670 3690 { 3671 3691 "name": "league/config", ··· 3805 3825 }, 3806 3826 { 3807 3827 "name": "league/flysystem", 3808 - "version": "3.15.1", 3828 + "version": "3.29.1", 3809 3829 "source": { 3810 3830 "type": "git", 3811 3831 "url": "https://github.com/thephpleague/flysystem.git", 3812 - "reference": "a141d430414fcb8bf797a18716b09f759a385bed" 3832 + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319" 3813 3833 }, 3814 3834 "dist": { 3815 3835 "type": "zip", 3816 - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a141d430414fcb8bf797a18716b09f759a385bed", 3817 - "reference": "a141d430414fcb8bf797a18716b09f759a385bed", 3836 + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319", 3837 + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319", 3818 3838 "shasum": "" 3819 3839 }, 3820 3840 "require": { ··· 3823 3843 "php": "^8.0.2" 3824 3844 }, 3825 3845 "conflict": { 3846 + "async-aws/core": "<1.19.0", 3847 + "async-aws/s3": "<1.14.0", 3826 3848 "aws/aws-sdk-php": "3.209.31 || 3.210.0", 3827 3849 "guzzlehttp/guzzle": "<7.0", 3828 3850 "guzzlehttp/ringphp": "<1.1.1", ··· 3830 3852 "symfony/http-client": "<5.2" 3831 3853 }, 3832 3854 "require-dev": { 3833 - "async-aws/s3": "^1.5", 3834 - "async-aws/simple-s3": "^1.1", 3835 - "aws/aws-sdk-php": "^3.220.0", 3855 + "async-aws/s3": "^1.5 || ^2.0", 3856 + "async-aws/simple-s3": "^1.1 || ^2.0", 3857 + "aws/aws-sdk-php": "^3.295.10", 3836 3858 "composer/semver": "^3.0", 3837 3859 "ext-fileinfo": "*", 3838 3860 "ext-ftp": "*", 3861 + "ext-mongodb": "^1.3", 3839 3862 "ext-zip": "*", 3840 3863 "friendsofphp/php-cs-fixer": "^3.5", 3841 3864 "google/cloud-storage": "^1.23", 3865 + "guzzlehttp/psr7": "^2.6", 3842 3866 "microsoft/azure-storage-blob": "^1.1", 3843 - "phpseclib/phpseclib": "^3.0.14", 3844 - "phpstan/phpstan": "^0.12.26", 3845 - "phpunit/phpunit": "^9.5.11", 3846 - "sabre/dav": "^4.3.1" 3867 + "mongodb/mongodb": "^1.2", 3868 + "phpseclib/phpseclib": "^3.0.36", 3869 + "phpstan/phpstan": "^1.10", 3870 + "phpunit/phpunit": "^9.5.11|^10.0", 3871 + "sabre/dav": "^4.6.0" 3847 3872 }, 3848 3873 "type": "library", 3849 3874 "autoload": { ··· 3877 3902 ], 3878 3903 "support": { 3879 3904 "issues": "https://github.com/thephpleague/flysystem/issues", 3880 - "source": "https://github.com/thephpleague/flysystem/tree/3.15.1" 3905 + "source": "https://github.com/thephpleague/flysystem/tree/3.29.1" 3881 3906 }, 3882 - "funding": [ 3883 - { 3884 - "url": "https://ecologi.com/frankdejonge", 3885 - "type": "custom" 3886 - }, 3887 - { 3888 - "url": "https://github.com/frankdejonge", 3889 - "type": "github" 3890 - } 3891 - ], 3892 - "time": "2023-05-04T09:04:26+00:00" 3907 + "time": "2024-10-08T08:58:34+00:00" 3893 3908 }, 3894 3909 { 3895 3910 "name": "league/flysystem-aws-s3-v3", ··· 3959 3974 }, 3960 3975 { 3961 3976 "name": "league/flysystem-local", 3962 - "version": "3.15.0", 3977 + "version": "3.29.0", 3963 3978 "source": { 3964 3979 "type": "git", 3965 3980 "url": "https://github.com/thephpleague/flysystem-local.git", 3966 - "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3" 3981 + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27" 3967 3982 }, 3968 3983 "dist": { 3969 3984 "type": "zip", 3970 - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/543f64c397fefdf9cfeac443ffb6beff602796b3", 3971 - "reference": "543f64c397fefdf9cfeac443ffb6beff602796b3", 3985 + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27", 3986 + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27", 3972 3987 "shasum": "" 3973 3988 }, 3974 3989 "require": { ··· 4002 4017 "local" 4003 4018 ], 4004 4019 "support": { 4005 - "issues": "https://github.com/thephpleague/flysystem-local/issues", 4006 - "source": "https://github.com/thephpleague/flysystem-local/tree/3.15.0" 4020 + "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0" 4007 4021 }, 4008 - "funding": [ 4009 - { 4010 - "url": "https://ecologi.com/frankdejonge", 4011 - "type": "custom" 4012 - }, 4013 - { 4014 - "url": "https://github.com/frankdejonge", 4015 - "type": "github" 4016 - } 4017 - ], 4018 - "time": "2023-05-02T20:02:14+00:00" 4022 + "time": "2024-08-09T21:24:39+00:00" 4019 4023 }, 4020 4024 { 4021 4025 "name": "league/fractal", ··· 4089 4093 }, 4090 4094 { 4091 4095 "name": "league/mime-type-detection", 4092 - "version": "1.11.0", 4096 + "version": "1.16.0", 4093 4097 "source": { 4094 4098 "type": "git", 4095 4099 "url": "https://github.com/thephpleague/mime-type-detection.git", 4096 - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" 4100 + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" 4097 4101 }, 4098 4102 "dist": { 4099 4103 "type": "zip", 4100 - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", 4101 - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", 4104 + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", 4105 + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", 4102 4106 "shasum": "" 4103 4107 }, 4104 4108 "require": { 4105 4109 "ext-fileinfo": "*", 4106 - "php": "^7.2 || ^8.0" 4110 + "php": "^7.4 || ^8.0" 4107 4111 }, 4108 4112 "require-dev": { 4109 4113 "friendsofphp/php-cs-fixer": "^3.2", 4110 4114 "phpstan/phpstan": "^0.12.68", 4111 - "phpunit/phpunit": "^8.5.8 || ^9.3" 4115 + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" 4112 4116 }, 4113 4117 "type": "library", 4114 4118 "autoload": { ··· 4129 4133 "description": "Mime-type detection for Flysystem", 4130 4134 "support": { 4131 4135 "issues": "https://github.com/thephpleague/mime-type-detection/issues", 4132 - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" 4136 + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" 4133 4137 }, 4134 4138 "funding": [ 4135 4139 { ··· 4141 4145 "type": "tidelift" 4142 4146 } 4143 4147 ], 4144 - "time": "2022-04-17T13:12:02+00:00" 4148 + "time": "2024-09-21T08:32:55+00:00" 4145 4149 }, 4146 4150 { 4147 4151 "name": "league/oauth2-client", ··· 4770 4774 }, 4771 4775 { 4772 4776 "name": "monolog/monolog", 4773 - "version": "3.4.0", 4777 + "version": "3.8.0", 4774 4778 "source": { 4775 4779 "type": "git", 4776 4780 "url": "https://github.com/Seldaek/monolog.git", 4777 - "reference": "e2392369686d420ca32df3803de28b5d6f76867d" 4781 + "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67" 4778 4782 }, 4779 4783 "dist": { 4780 4784 "type": "zip", 4781 - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/e2392369686d420ca32df3803de28b5d6f76867d", 4782 - "reference": "e2392369686d420ca32df3803de28b5d6f76867d", 4785 + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67", 4786 + "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67", 4783 4787 "shasum": "" 4784 4788 }, 4785 4789 "require": { ··· 4799 4803 "guzzlehttp/psr7": "^2.2", 4800 4804 "mongodb/mongodb": "^1.8", 4801 4805 "php-amqplib/php-amqplib": "~2.4 || ^3", 4802 - "phpstan/phpstan": "^1.9", 4803 - "phpstan/phpstan-deprecation-rules": "^1.0", 4804 - "phpstan/phpstan-strict-rules": "^1.4", 4805 - "phpunit/phpunit": "^10.1", 4806 + "php-console/php-console": "^3.1.8", 4807 + "phpstan/phpstan": "^2", 4808 + "phpstan/phpstan-deprecation-rules": "^2", 4809 + "phpstan/phpstan-strict-rules": "^2", 4810 + "phpunit/phpunit": "^10.5.17 || ^11.0.7", 4806 4811 "predis/predis": "^1.1 || ^2", 4807 - "ruflin/elastica": "^7", 4812 + "rollbar/rollbar": "^4.0", 4813 + "ruflin/elastica": "^7 || ^8", 4808 4814 "symfony/mailer": "^5.4 || ^6", 4809 4815 "symfony/mime": "^5.4 || ^6" 4810 4816 }, ··· 4855 4861 ], 4856 4862 "support": { 4857 4863 "issues": "https://github.com/Seldaek/monolog/issues", 4858 - "source": "https://github.com/Seldaek/monolog/tree/3.4.0" 4864 + "source": "https://github.com/Seldaek/monolog/tree/3.8.0" 4859 4865 }, 4860 4866 "funding": [ 4861 4867 { ··· 4867 4873 "type": "tidelift" 4868 4874 } 4869 4875 ], 4870 - "time": "2023-06-21T08:46:11+00:00" 4876 + "time": "2024-11-12T13:57:08+00:00" 4871 4877 }, 4872 4878 { 4873 4879 "name": "mpociot/reflection-docblock", ··· 5053 5059 }, 5054 5060 { 5055 5061 "name": "nesbot/carbon", 5056 - "version": "2.72.1", 5062 + "version": "2.72.5", 5057 5063 "source": { 5058 5064 "type": "git", 5059 5065 "url": "https://github.com/briannesbitt/Carbon.git", 5060 - "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78" 5066 + "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed" 5061 5067 }, 5062 5068 "dist": { 5063 5069 "type": "zip", 5064 - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2b3b3db0a2d0556a177392ff1a3bf5608fa09f78", 5065 - "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78", 5070 + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/afd46589c216118ecd48ff2b95d77596af1e57ed", 5071 + "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed", 5066 5072 "shasum": "" 5067 5073 }, 5068 5074 "require": { ··· 5096 5102 "type": "library", 5097 5103 "extra": { 5098 5104 "branch-alias": { 5099 - "dev-3.x": "3.x-dev", 5100 - "dev-master": "2.x-dev" 5105 + "dev-master": "3.x-dev", 5106 + "dev-2.x": "2.x-dev" 5101 5107 }, 5102 5108 "laravel": { 5103 5109 "providers": [ ··· 5156 5162 "type": "tidelift" 5157 5163 } 5158 5164 ], 5159 - "time": "2023-12-08T23:47:49+00:00" 5165 + "time": "2024-06-03T19:18:41+00:00" 5160 5166 }, 5161 5167 { 5162 5168 "name": "nette/schema", 5163 - "version": "v1.2.5", 5169 + "version": "v1.3.2", 5164 5170 "source": { 5165 5171 "type": "git", 5166 5172 "url": "https://github.com/nette/schema.git", 5167 - "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a" 5173 + "reference": "da801d52f0354f70a638673c4a0f04e16529431d" 5168 5174 }, 5169 5175 "dist": { 5170 5176 "type": "zip", 5171 - "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a", 5172 - "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a", 5177 + "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", 5178 + "reference": "da801d52f0354f70a638673c4a0f04e16529431d", 5173 5179 "shasum": "" 5174 5180 }, 5175 5181 "require": { 5176 - "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0", 5177 - "php": "7.1 - 8.3" 5182 + "nette/utils": "^4.0", 5183 + "php": "8.1 - 8.4" 5178 5184 }, 5179 5185 "require-dev": { 5180 - "nette/tester": "^2.3 || ^2.4", 5186 + "nette/tester": "^2.5.2", 5181 5187 "phpstan/phpstan-nette": "^1.0", 5182 - "tracy/tracy": "^2.7" 5188 + "tracy/tracy": "^2.8" 5183 5189 }, 5184 5190 "type": "library", 5185 5191 "extra": { 5186 5192 "branch-alias": { 5187 - "dev-master": "1.2-dev" 5193 + "dev-master": "1.3-dev" 5188 5194 } 5189 5195 }, 5190 5196 "autoload": { ··· 5216 5222 ], 5217 5223 "support": { 5218 5224 "issues": "https://github.com/nette/schema/issues", 5219 - "source": "https://github.com/nette/schema/tree/v1.2.5" 5225 + "source": "https://github.com/nette/schema/tree/v1.3.2" 5220 5226 }, 5221 - "time": "2023-10-05T20:37:59+00:00" 5227 + "time": "2024-10-06T23:10:23+00:00" 5222 5228 }, 5223 5229 { 5224 5230 "name": "nette/utils", 5225 - "version": "v4.0.4", 5231 + "version": "v4.0.5", 5226 5232 "source": { 5227 5233 "type": "git", 5228 5234 "url": "https://github.com/nette/utils.git", 5229 - "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218" 5235 + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96" 5230 5236 }, 5231 5237 "dist": { 5232 5238 "type": "zip", 5233 - "url": "https://api.github.com/repos/nette/utils/zipball/d3ad0aa3b9f934602cb3e3902ebccf10be34d218", 5234 - "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218", 5239 + "url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", 5240 + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", 5235 5241 "shasum": "" 5236 5242 }, 5237 5243 "require": { 5238 - "php": ">=8.0 <8.4" 5244 + "php": "8.0 - 8.4" 5239 5245 }, 5240 5246 "conflict": { 5241 5247 "nette/finder": "<3", ··· 5302 5308 ], 5303 5309 "support": { 5304 5310 "issues": "https://github.com/nette/utils/issues", 5305 - "source": "https://github.com/nette/utils/tree/v4.0.4" 5311 + "source": "https://github.com/nette/utils/tree/v4.0.5" 5306 5312 }, 5307 - "time": "2024-01-17T16:50:36+00:00" 5313 + "time": "2024-08-07T15:39:19+00:00" 5308 5314 }, 5309 5315 { 5310 5316 "name": "nikic/php-parser", ··· 5452 5458 }, 5453 5459 { 5454 5460 "name": "nunomaduro/termwind", 5455 - "version": "v1.15.1", 5461 + "version": "v1.16.0", 5456 5462 "source": { 5457 5463 "type": "git", 5458 5464 "url": "https://github.com/nunomaduro/termwind.git", 5459 - "reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc" 5465 + "reference": "dcf1ec3dfa36137b7ce41d43866644a7ab8fc257" 5460 5466 }, 5461 5467 "dist": { 5462 5468 "type": "zip", 5463 - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/8ab0b32c8caa4a2e09700ea32925441385e4a5dc", 5464 - "reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc", 5469 + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dcf1ec3dfa36137b7ce41d43866644a7ab8fc257", 5470 + "reference": "dcf1ec3dfa36137b7ce41d43866644a7ab8fc257", 5465 5471 "shasum": "" 5466 5472 }, 5467 5473 "require": { 5468 5474 "ext-mbstring": "*", 5469 - "php": "^8.0", 5470 - "symfony/console": "^5.3.0|^6.0.0" 5475 + "php": "^8.1", 5476 + "symfony/console": "^6.4.12" 5471 5477 }, 5472 5478 "require-dev": { 5473 - "ergebnis/phpstan-rules": "^1.0.", 5474 - "illuminate/console": "^8.0|^9.0", 5475 - "illuminate/support": "^8.0|^9.0", 5476 - "laravel/pint": "^1.0.0", 5477 - "pestphp/pest": "^1.21.0", 5478 - "pestphp/pest-plugin-mock": "^1.0", 5479 - "phpstan/phpstan": "^1.4.6", 5480 - "phpstan/phpstan-strict-rules": "^1.1.0", 5481 - "symfony/var-dumper": "^5.2.7|^6.0.0", 5479 + "illuminate/console": "^10.48.22", 5480 + "illuminate/support": "^10.48.22", 5481 + "laravel/pint": "^1.18.1", 5482 + "pestphp/pest": "^2", 5483 + "pestphp/pest-plugin-mock": "2.0.0", 5484 + "phpstan/phpstan": "^1.12.6", 5485 + "phpstan/phpstan-strict-rules": "^1.6.1", 5486 + "symfony/var-dumper": "^6.4.11", 5482 5487 "thecodingmachine/phpstan-strict-rules": "^1.0.0" 5483 5488 }, 5484 5489 "type": "library", ··· 5518 5523 ], 5519 5524 "support": { 5520 5525 "issues": "https://github.com/nunomaduro/termwind/issues", 5521 - "source": "https://github.com/nunomaduro/termwind/tree/v1.15.1" 5526 + "source": "https://github.com/nunomaduro/termwind/tree/v1.16.0" 5522 5527 }, 5523 5528 "funding": [ 5524 5529 { ··· 5534 5539 "type": "github" 5535 5540 } 5536 5541 ], 5537 - "time": "2023-02-08T01:06:31+00:00" 5542 + "time": "2024-10-15T15:27:12+00:00" 5538 5543 }, 5539 5544 { 5540 5545 "name": "nyholm/psr7", ··· 6324 6329 }, 6325 6330 { 6326 6331 "name": "phpoption/phpoption", 6327 - "version": "1.9.1", 6332 + "version": "1.9.3", 6328 6333 "source": { 6329 6334 "type": "git", 6330 6335 "url": "https://github.com/schmittjoh/php-option.git", 6331 - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" 6336 + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" 6332 6337 }, 6333 6338 "dist": { 6334 6339 "type": "zip", 6335 - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", 6336 - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", 6340 + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", 6341 + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", 6337 6342 "shasum": "" 6338 6343 }, 6339 6344 "require": { ··· 6341 6346 }, 6342 6347 "require-dev": { 6343 6348 "bamarni/composer-bin-plugin": "^1.8.2", 6344 - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" 6349 + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" 6345 6350 }, 6346 6351 "type": "library", 6347 6352 "extra": { 6348 6353 "bamarni-bin": { 6349 6354 "bin-links": true, 6350 - "forward-command": true 6355 + "forward-command": false 6351 6356 }, 6352 6357 "branch-alias": { 6353 6358 "dev-master": "1.9-dev" ··· 6383 6388 ], 6384 6389 "support": { 6385 6390 "issues": "https://github.com/schmittjoh/php-option/issues", 6386 - "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" 6391 + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" 6387 6392 }, 6388 6393 "funding": [ 6389 6394 { ··· 6395 6400 "type": "tidelift" 6396 6401 } 6397 6402 ], 6398 - "time": "2023-02-25T19:38:58+00:00" 6403 + "time": "2024-07-20T21:41:07+00:00" 6399 6404 }, 6400 6405 { 6401 6406 "name": "phpseclib/phpseclib", ··· 6869 6874 }, 6870 6875 { 6871 6876 "name": "psr/log", 6872 - "version": "3.0.0", 6877 + "version": "3.0.2", 6873 6878 "source": { 6874 6879 "type": "git", 6875 6880 "url": "https://github.com/php-fig/log.git", 6876 - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" 6881 + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" 6877 6882 }, 6878 6883 "dist": { 6879 6884 "type": "zip", 6880 - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", 6881 - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", 6885 + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 6886 + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 6882 6887 "shasum": "" 6883 6888 }, 6884 6889 "require": { ··· 6913 6918 "psr-3" 6914 6919 ], 6915 6920 "support": { 6916 - "source": "https://github.com/php-fig/log/tree/3.0.0" 6921 + "source": "https://github.com/php-fig/log/tree/3.0.2" 6917 6922 }, 6918 - "time": "2021-07-14T16:46:02+00:00" 6923 + "time": "2024-09-11T13:17:53+00:00" 6919 6924 }, 6920 6925 { 6921 6926 "name": "psr/simple-cache", ··· 7179 7184 }, 7180 7185 { 7181 7186 "name": "ramsey/uuid", 7182 - "version": "4.7.4", 7187 + "version": "4.7.6", 7183 7188 "source": { 7184 7189 "type": "git", 7185 7190 "url": "https://github.com/ramsey/uuid.git", 7186 - "reference": "60a4c63ab724854332900504274f6150ff26d286" 7191 + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" 7187 7192 }, 7188 7193 "dist": { 7189 7194 "type": "zip", 7190 - "url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286", 7191 - "reference": "60a4c63ab724854332900504274f6150ff26d286", 7195 + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", 7196 + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", 7192 7197 "shasum": "" 7193 7198 }, 7194 7199 "require": { 7195 - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", 7200 + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", 7196 7201 "ext-json": "*", 7197 7202 "php": "^8.0", 7198 7203 "ramsey/collection": "^1.2 || ^2.0" ··· 7255 7260 ], 7256 7261 "support": { 7257 7262 "issues": "https://github.com/ramsey/uuid/issues", 7258 - "source": "https://github.com/ramsey/uuid/tree/4.7.4" 7263 + "source": "https://github.com/ramsey/uuid/tree/4.7.6" 7259 7264 }, 7260 7265 "funding": [ 7261 7266 { ··· 7267 7272 "type": "tidelift" 7268 7273 } 7269 7274 ], 7270 - "time": "2023-04-15T23:01:58+00:00" 7275 + "time": "2024-04-27T21:32:50+00:00" 7271 7276 }, 7272 7277 { 7273 7278 "name": "react/promise", ··· 7636 7641 }, 7637 7642 { 7638 7643 "name": "sentry/sentry-laravel", 7639 - "version": "3.5.1", 7644 + "version": "3.8.2", 7640 7645 "source": { 7641 7646 "type": "git", 7642 7647 "url": "https://github.com/getsentry/sentry-laravel.git", 7643 - "reference": "85c2168e469ca73ee90de5e71cef53153e949e64" 7648 + "reference": "1293e5732f8405e12f000cdf5dee78c927a18de0" 7644 7649 }, 7645 7650 "dist": { 7646 7651 "type": "zip", 7647 - "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/85c2168e469ca73ee90de5e71cef53153e949e64", 7648 - "reference": "85c2168e469ca73ee90de5e71cef53153e949e64", 7652 + "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/1293e5732f8405e12f000cdf5dee78c927a18de0", 7653 + "reference": "1293e5732f8405e12f000cdf5dee78c927a18de0", 7649 7654 "shasum": "" 7650 7655 }, 7651 7656 "require": { ··· 7653 7658 "nyholm/psr7": "^1.0", 7654 7659 "php": "^7.2 | ^8.0", 7655 7660 "sentry/sdk": "^3.4", 7656 - "sentry/sentry": "^3.19", 7661 + "sentry/sentry": "^3.20.1", 7657 7662 "symfony/psr-http-message-bridge": "^1.0 | ^2.0" 7658 7663 }, 7659 7664 "require-dev": { 7660 7665 "friendsofphp/php-cs-fixer": "^3.11", 7666 + "laravel/folio": "^1.0", 7661 7667 "laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0", 7662 7668 "mockery/mockery": "^1.3", 7663 7669 "orchestra/testbench": "^4.7 | ^5.1 | ^6.0 | ^7.0 | ^8.0", 7670 + "phpstan/phpstan": "^1.10", 7664 7671 "phpunit/phpunit": "^8.4 | ^9.3" 7665 7672 }, 7666 7673 "type": "library", ··· 7710 7717 ], 7711 7718 "support": { 7712 7719 "issues": "https://github.com/getsentry/sentry-laravel/issues", 7713 - "source": "https://github.com/getsentry/sentry-laravel/tree/3.5.1" 7720 + "source": "https://github.com/getsentry/sentry-laravel/tree/3.8.2" 7714 7721 }, 7715 7722 "funding": [ 7716 7723 { ··· 7722 7729 "type": "custom" 7723 7730 } 7724 7731 ], 7725 - "time": "2023-06-20T13:19:32+00:00" 7732 + "time": "2023-10-12T14:38:46+00:00" 7726 7733 }, 7727 7734 { 7728 7735 "name": "shalvah/clara", ··· 8065 8072 }, 8066 8073 { 8067 8074 "name": "symfony/cache-contracts", 8068 - "version": "v3.4.0", 8075 + "version": "v3.5.0", 8069 8076 "source": { 8070 8077 "type": "git", 8071 8078 "url": "https://github.com/symfony/cache-contracts.git", 8072 - "reference": "1d74b127da04ffa87aa940abe15446fa89653778" 8079 + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197" 8073 8080 }, 8074 8081 "dist": { 8075 8082 "type": "zip", 8076 - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/1d74b127da04ffa87aa940abe15446fa89653778", 8077 - "reference": "1d74b127da04ffa87aa940abe15446fa89653778", 8083 + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/df6a1a44c890faded49a5fca33c2d5c5fd3c2197", 8084 + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197", 8078 8085 "shasum": "" 8079 8086 }, 8080 8087 "require": { ··· 8084 8091 "type": "library", 8085 8092 "extra": { 8086 8093 "branch-alias": { 8087 - "dev-main": "3.4-dev" 8094 + "dev-main": "3.5-dev" 8088 8095 }, 8089 8096 "thanks": { 8090 8097 "name": "symfony/contracts", ··· 8121 8128 "standards" 8122 8129 ], 8123 8130 "support": { 8124 - "source": "https://github.com/symfony/cache-contracts/tree/v3.4.0" 8131 + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.0" 8125 8132 }, 8126 8133 "funding": [ 8127 8134 { ··· 8137 8144 "type": "tidelift" 8138 8145 } 8139 8146 ], 8140 - "time": "2023-09-25T12:52:38+00:00" 8147 + "time": "2024-04-18T09:32:20+00:00" 8141 8148 }, 8142 8149 { 8143 8150 "name": "symfony/console", 8144 - "version": "v6.3.0", 8151 + "version": "v6.4.14", 8145 8152 "source": { 8146 8153 "type": "git", 8147 8154 "url": "https://github.com/symfony/console.git", 8148 - "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7" 8155 + "reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b" 8149 8156 }, 8150 8157 "dist": { 8151 8158 "type": "zip", 8152 - "url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", 8153 - "reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7", 8159 + "url": "https://api.github.com/repos/symfony/console/zipball/897c2441ed4eec8a8a2c37b943427d24dba3f26b", 8160 + "reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b", 8154 8161 "shasum": "" 8155 8162 }, 8156 8163 "require": { ··· 8158 8165 "symfony/deprecation-contracts": "^2.5|^3", 8159 8166 "symfony/polyfill-mbstring": "~1.0", 8160 8167 "symfony/service-contracts": "^2.5|^3", 8161 - "symfony/string": "^5.4|^6.0" 8168 + "symfony/string": "^5.4|^6.0|^7.0" 8162 8169 }, 8163 8170 "conflict": { 8164 8171 "symfony/dependency-injection": "<5.4", ··· 8172 8179 }, 8173 8180 "require-dev": { 8174 8181 "psr/log": "^1|^2|^3", 8175 - "symfony/config": "^5.4|^6.0", 8176 - "symfony/dependency-injection": "^5.4|^6.0", 8177 - "symfony/event-dispatcher": "^5.4|^6.0", 8178 - "symfony/lock": "^5.4|^6.0", 8179 - "symfony/process": "^5.4|^6.0", 8180 - "symfony/var-dumper": "^5.4|^6.0" 8182 + "symfony/config": "^5.4|^6.0|^7.0", 8183 + "symfony/dependency-injection": "^5.4|^6.0|^7.0", 8184 + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", 8185 + "symfony/http-foundation": "^6.4|^7.0", 8186 + "symfony/http-kernel": "^6.4|^7.0", 8187 + "symfony/lock": "^5.4|^6.0|^7.0", 8188 + "symfony/messenger": "^5.4|^6.0|^7.0", 8189 + "symfony/process": "^5.4|^6.0|^7.0", 8190 + "symfony/stopwatch": "^5.4|^6.0|^7.0", 8191 + "symfony/var-dumper": "^5.4|^6.0|^7.0" 8181 8192 }, 8182 8193 "type": "library", 8183 8194 "autoload": { ··· 8211 8222 "terminal" 8212 8223 ], 8213 8224 "support": { 8214 - "source": "https://github.com/symfony/console/tree/v6.3.0" 8225 + "source": "https://github.com/symfony/console/tree/v6.4.14" 8215 8226 }, 8216 8227 "funding": [ 8217 8228 { ··· 8227 8238 "type": "tidelift" 8228 8239 } 8229 8240 ], 8230 - "time": "2023-05-29T12:49:39+00:00" 8241 + "time": "2024-11-05T15:34:40+00:00" 8231 8242 }, 8232 8243 { 8233 8244 "name": "symfony/css-selector", 8234 - "version": "v6.3.0", 8245 + "version": "v7.1.6", 8235 8246 "source": { 8236 8247 "type": "git", 8237 8248 "url": "https://github.com/symfony/css-selector.git", 8238 - "reference": "88453e64cd86c5b60e8d2fb2c6f953bbc353ffbf" 8249 + "reference": "4aa4f6b3d6749c14d3aa815eef8226632e7bbc66" 8239 8250 }, 8240 8251 "dist": { 8241 8252 "type": "zip", 8242 - "url": "https://api.github.com/repos/symfony/css-selector/zipball/88453e64cd86c5b60e8d2fb2c6f953bbc353ffbf", 8243 - "reference": "88453e64cd86c5b60e8d2fb2c6f953bbc353ffbf", 8253 + "url": "https://api.github.com/repos/symfony/css-selector/zipball/4aa4f6b3d6749c14d3aa815eef8226632e7bbc66", 8254 + "reference": "4aa4f6b3d6749c14d3aa815eef8226632e7bbc66", 8244 8255 "shasum": "" 8245 8256 }, 8246 8257 "require": { 8247 - "php": ">=8.1" 8258 + "php": ">=8.2" 8248 8259 }, 8249 8260 "type": "library", 8250 8261 "autoload": { ··· 8276 8287 "description": "Converts CSS selectors to XPath expressions", 8277 8288 "homepage": "https://symfony.com", 8278 8289 "support": { 8279 - "source": "https://github.com/symfony/css-selector/tree/v6.3.0" 8290 + "source": "https://github.com/symfony/css-selector/tree/v7.1.6" 8280 8291 }, 8281 8292 "funding": [ 8282 8293 { ··· 8292 8303 "type": "tidelift" 8293 8304 } 8294 8305 ], 8295 - "time": "2023-03-20T16:43:42+00:00" 8306 + "time": "2024-09-25T14:20:29+00:00" 8296 8307 }, 8297 8308 { 8298 8309 "name": "symfony/deprecation-contracts", 8299 - "version": "v3.4.0", 8310 + "version": "v3.5.0", 8300 8311 "source": { 8301 8312 "type": "git", 8302 8313 "url": "https://github.com/symfony/deprecation-contracts.git", 8303 - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" 8314 + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" 8304 8315 }, 8305 8316 "dist": { 8306 8317 "type": "zip", 8307 - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", 8308 - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", 8318 + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", 8319 + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", 8309 8320 "shasum": "" 8310 8321 }, 8311 8322 "require": { ··· 8314 8325 "type": "library", 8315 8326 "extra": { 8316 8327 "branch-alias": { 8317 - "dev-main": "3.4-dev" 8328 + "dev-main": "3.5-dev" 8318 8329 }, 8319 8330 "thanks": { 8320 8331 "name": "symfony/contracts", ··· 8343 8354 "description": "A generic function and convention to trigger deprecation notices", 8344 8355 "homepage": "https://symfony.com", 8345 8356 "support": { 8346 - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" 8357 + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" 8347 8358 }, 8348 8359 "funding": [ 8349 8360 { ··· 8359 8370 "type": "tidelift" 8360 8371 } 8361 8372 ], 8362 - "time": "2023-05-23T14:45:45+00:00" 8373 + "time": "2024-04-18T09:32:20+00:00" 8363 8374 }, 8364 8375 { 8365 8376 "name": "symfony/error-handler", 8366 - "version": "v6.3.0", 8377 + "version": "v6.4.14", 8367 8378 "source": { 8368 8379 "type": "git", 8369 8380 "url": "https://github.com/symfony/error-handler.git", 8370 - "reference": "99d2d814a6351461af350ead4d963bd67451236f" 8381 + "reference": "9e024324511eeb00983ee76b9aedc3e6ecd993d9" 8371 8382 }, 8372 8383 "dist": { 8373 8384 "type": "zip", 8374 - "url": "https://api.github.com/repos/symfony/error-handler/zipball/99d2d814a6351461af350ead4d963bd67451236f", 8375 - "reference": "99d2d814a6351461af350ead4d963bd67451236f", 8385 + "url": "https://api.github.com/repos/symfony/error-handler/zipball/9e024324511eeb00983ee76b9aedc3e6ecd993d9", 8386 + "reference": "9e024324511eeb00983ee76b9aedc3e6ecd993d9", 8376 8387 "shasum": "" 8377 8388 }, 8378 8389 "require": { 8379 8390 "php": ">=8.1", 8380 8391 "psr/log": "^1|^2|^3", 8381 - "symfony/var-dumper": "^5.4|^6.0" 8392 + "symfony/var-dumper": "^5.4|^6.0|^7.0" 8382 8393 }, 8383 8394 "conflict": { 8384 - "symfony/deprecation-contracts": "<2.5" 8395 + "symfony/deprecation-contracts": "<2.5", 8396 + "symfony/http-kernel": "<6.4" 8385 8397 }, 8386 8398 "require-dev": { 8387 8399 "symfony/deprecation-contracts": "^2.5|^3", 8388 - "symfony/http-kernel": "^5.4|^6.0", 8389 - "symfony/serializer": "^5.4|^6.0" 8400 + "symfony/http-kernel": "^6.4|^7.0", 8401 + "symfony/serializer": "^5.4|^6.0|^7.0" 8390 8402 }, 8391 8403 "bin": [ 8392 8404 "Resources/bin/patch-type-declarations" ··· 8417 8429 "description": "Provides tools to manage errors and ease debugging PHP code", 8418 8430 "homepage": "https://symfony.com", 8419 8431 "support": { 8420 - "source": "https://github.com/symfony/error-handler/tree/v6.3.0" 8432 + "source": "https://github.com/symfony/error-handler/tree/v6.4.14" 8421 8433 }, 8422 8434 "funding": [ 8423 8435 { ··· 8433 8445 "type": "tidelift" 8434 8446 } 8435 8447 ], 8436 - "time": "2023-05-10T12:03:13+00:00" 8448 + "time": "2024-11-05T15:34:40+00:00" 8437 8449 }, 8438 8450 { 8439 8451 "name": "symfony/event-dispatcher", 8440 - "version": "v6.3.0", 8452 + "version": "v7.1.6", 8441 8453 "source": { 8442 8454 "type": "git", 8443 8455 "url": "https://github.com/symfony/event-dispatcher.git", 8444 - "reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa" 8456 + "reference": "87254c78dd50721cfd015b62277a8281c5589702" 8445 8457 }, 8446 8458 "dist": { 8447 8459 "type": "zip", 8448 - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa", 8449 - "reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa", 8460 + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87254c78dd50721cfd015b62277a8281c5589702", 8461 + "reference": "87254c78dd50721cfd015b62277a8281c5589702", 8450 8462 "shasum": "" 8451 8463 }, 8452 8464 "require": { 8453 - "php": ">=8.1", 8465 + "php": ">=8.2", 8454 8466 "symfony/event-dispatcher-contracts": "^2.5|^3" 8455 8467 }, 8456 8468 "conflict": { 8457 - "symfony/dependency-injection": "<5.4", 8469 + "symfony/dependency-injection": "<6.4", 8458 8470 "symfony/service-contracts": "<2.5" 8459 8471 }, 8460 8472 "provide": { ··· 8463 8475 }, 8464 8476 "require-dev": { 8465 8477 "psr/log": "^1|^2|^3", 8466 - "symfony/config": "^5.4|^6.0", 8467 - "symfony/dependency-injection": "^5.4|^6.0", 8468 - "symfony/error-handler": "^5.4|^6.0", 8469 - "symfony/expression-language": "^5.4|^6.0", 8470 - "symfony/http-foundation": "^5.4|^6.0", 8478 + "symfony/config": "^6.4|^7.0", 8479 + "symfony/dependency-injection": "^6.4|^7.0", 8480 + "symfony/error-handler": "^6.4|^7.0", 8481 + "symfony/expression-language": "^6.4|^7.0", 8482 + "symfony/http-foundation": "^6.4|^7.0", 8471 8483 "symfony/service-contracts": "^2.5|^3", 8472 - "symfony/stopwatch": "^5.4|^6.0" 8484 + "symfony/stopwatch": "^6.4|^7.0" 8473 8485 }, 8474 8486 "type": "library", 8475 8487 "autoload": { ··· 8497 8509 "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", 8498 8510 "homepage": "https://symfony.com", 8499 8511 "support": { 8500 - "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.0" 8512 + "source": "https://github.com/symfony/event-dispatcher/tree/v7.1.6" 8501 8513 }, 8502 8514 "funding": [ 8503 8515 { ··· 8513 8525 "type": "tidelift" 8514 8526 } 8515 8527 ], 8516 - "time": "2023-04-21T14:41:17+00:00" 8528 + "time": "2024-09-25T14:20:29+00:00" 8517 8529 }, 8518 8530 { 8519 8531 "name": "symfony/event-dispatcher-contracts", 8520 - "version": "v3.4.0", 8532 + "version": "v3.5.0", 8521 8533 "source": { 8522 8534 "type": "git", 8523 8535 "url": "https://github.com/symfony/event-dispatcher-contracts.git", 8524 - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" 8536 + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" 8525 8537 }, 8526 8538 "dist": { 8527 8539 "type": "zip", 8528 - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", 8529 - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", 8540 + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", 8541 + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", 8530 8542 "shasum": "" 8531 8543 }, 8532 8544 "require": { ··· 8536 8548 "type": "library", 8537 8549 "extra": { 8538 8550 "branch-alias": { 8539 - "dev-main": "3.4-dev" 8551 + "dev-main": "3.5-dev" 8540 8552 }, 8541 8553 "thanks": { 8542 8554 "name": "symfony/contracts", ··· 8573 8585 "standards" 8574 8586 ], 8575 8587 "support": { 8576 - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.0" 8588 + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0" 8577 8589 }, 8578 8590 "funding": [ 8579 8591 { ··· 8589 8601 "type": "tidelift" 8590 8602 } 8591 8603 ], 8592 - "time": "2023-05-23T14:45:45+00:00" 8604 + "time": "2024-04-18T09:32:20+00:00" 8593 8605 }, 8594 8606 { 8595 8607 "name": "symfony/finder", 8596 - "version": "v6.3.0", 8608 + "version": "v6.4.13", 8597 8609 "source": { 8598 8610 "type": "git", 8599 8611 "url": "https://github.com/symfony/finder.git", 8600 - "reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2" 8612 + "reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958" 8601 8613 }, 8602 8614 "dist": { 8603 8615 "type": "zip", 8604 - "url": "https://api.github.com/repos/symfony/finder/zipball/d9b01ba073c44cef617c7907ce2419f8d00d75e2", 8605 - "reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2", 8616 + "url": "https://api.github.com/repos/symfony/finder/zipball/daea9eca0b08d0ed1dc9ab702a46128fd1be4958", 8617 + "reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958", 8606 8618 "shasum": "" 8607 8619 }, 8608 8620 "require": { 8609 8621 "php": ">=8.1" 8610 8622 }, 8611 8623 "require-dev": { 8612 - "symfony/filesystem": "^6.0" 8624 + "symfony/filesystem": "^6.0|^7.0" 8613 8625 }, 8614 8626 "type": "library", 8615 8627 "autoload": { ··· 8637 8649 "description": "Finds files and directories via an intuitive fluent interface", 8638 8650 "homepage": "https://symfony.com", 8639 8651 "support": { 8640 - "source": "https://github.com/symfony/finder/tree/v6.3.0" 8652 + "source": "https://github.com/symfony/finder/tree/v6.4.13" 8641 8653 }, 8642 8654 "funding": [ 8643 8655 { ··· 8653 8665 "type": "tidelift" 8654 8666 } 8655 8667 ], 8656 - "time": "2023-04-02T01:25:41+00:00" 8668 + "time": "2024-10-01T08:30:56+00:00" 8657 8669 }, 8658 8670 { 8659 8671 "name": "symfony/http-client", 8660 - "version": "v6.3.1", 8672 + "version": "v6.4.15", 8661 8673 "source": { 8662 8674 "type": "git", 8663 8675 "url": "https://github.com/symfony/http-client.git", 8664 - "reference": "1c828a06aef2f5eeba42026dfc532d4fc5406123" 8676 + "reference": "cb4073c905cd12b8496d24ac428a9228c1750670" 8665 8677 }, 8666 8678 "dist": { 8667 8679 "type": "zip", 8668 - "url": "https://api.github.com/repos/symfony/http-client/zipball/1c828a06aef2f5eeba42026dfc532d4fc5406123", 8669 - "reference": "1c828a06aef2f5eeba42026dfc532d4fc5406123", 8680 + "url": "https://api.github.com/repos/symfony/http-client/zipball/cb4073c905cd12b8496d24ac428a9228c1750670", 8681 + "reference": "cb4073c905cd12b8496d24ac428a9228c1750670", 8670 8682 "shasum": "" 8671 8683 }, 8672 8684 "require": { 8673 8685 "php": ">=8.1", 8674 8686 "psr/log": "^1|^2|^3", 8675 8687 "symfony/deprecation-contracts": "^2.5|^3", 8676 - "symfony/http-client-contracts": "^3", 8688 + "symfony/http-client-contracts": "^3.4.1", 8677 8689 "symfony/service-contracts": "^2.5|^3" 8678 8690 }, 8679 8691 "conflict": { ··· 8691 8703 "amphp/http-client": "^4.2.1", 8692 8704 "amphp/http-tunnel": "^1.0", 8693 8705 "amphp/socket": "^1.1", 8694 - "guzzlehttp/promises": "^1.4", 8706 + "guzzlehttp/promises": "^1.4|^2.0", 8695 8707 "nyholm/psr7": "^1.0", 8696 8708 "php-http/httplug": "^1.0|^2.0", 8697 8709 "psr/http-client": "^1.0", 8698 - "symfony/dependency-injection": "^5.4|^6.0", 8699 - "symfony/http-kernel": "^5.4|^6.0", 8700 - "symfony/process": "^5.4|^6.0", 8701 - "symfony/stopwatch": "^5.4|^6.0" 8710 + "symfony/dependency-injection": "^5.4|^6.0|^7.0", 8711 + "symfony/http-kernel": "^5.4|^6.0|^7.0", 8712 + "symfony/messenger": "^5.4|^6.0|^7.0", 8713 + "symfony/process": "^5.4|^6.0|^7.0", 8714 + "symfony/stopwatch": "^5.4|^6.0|^7.0" 8702 8715 }, 8703 8716 "type": "library", 8704 8717 "autoload": { ··· 8729 8742 "http" 8730 8743 ], 8731 8744 "support": { 8732 - "source": "https://github.com/symfony/http-client/tree/v6.3.1" 8745 + "source": "https://github.com/symfony/http-client/tree/v6.4.15" 8733 8746 }, 8734 8747 "funding": [ 8735 8748 { ··· 8745 8758 "type": "tidelift" 8746 8759 } 8747 8760 ], 8748 - "time": "2023-06-24T11:51:27+00:00" 8761 + "time": "2024-11-13T13:40:18+00:00" 8749 8762 }, 8750 8763 { 8751 8764 "name": "symfony/http-client-contracts", 8752 - "version": "v3.4.0", 8765 + "version": "v3.5.0", 8753 8766 "source": { 8754 8767 "type": "git", 8755 8768 "url": "https://github.com/symfony/http-client-contracts.git", 8756 - "reference": "1ee70e699b41909c209a0c930f11034b93578654" 8769 + "reference": "20414d96f391677bf80078aa55baece78b82647d" 8757 8770 }, 8758 8771 "dist": { 8759 8772 "type": "zip", 8760 - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/1ee70e699b41909c209a0c930f11034b93578654", 8761 - "reference": "1ee70e699b41909c209a0c930f11034b93578654", 8773 + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", 8774 + "reference": "20414d96f391677bf80078aa55baece78b82647d", 8762 8775 "shasum": "" 8763 8776 }, 8764 8777 "require": { ··· 8767 8780 "type": "library", 8768 8781 "extra": { 8769 8782 "branch-alias": { 8770 - "dev-main": "3.4-dev" 8783 + "dev-main": "3.5-dev" 8771 8784 }, 8772 8785 "thanks": { 8773 8786 "name": "symfony/contracts", ··· 8807 8820 "standards" 8808 8821 ], 8809 8822 "support": { 8810 - "source": "https://github.com/symfony/http-client-contracts/tree/v3.4.0" 8823 + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" 8811 8824 }, 8812 8825 "funding": [ 8813 8826 { ··· 8823 8836 "type": "tidelift" 8824 8837 } 8825 8838 ], 8826 - "time": "2023-07-30T20:28:31+00:00" 8839 + "time": "2024-04-18T09:32:20+00:00" 8827 8840 }, 8828 8841 { 8829 8842 "name": "symfony/http-foundation", 8830 - "version": "v6.4.2", 8843 + "version": "v6.4.14", 8831 8844 "source": { 8832 8845 "type": "git", 8833 8846 "url": "https://github.com/symfony/http-foundation.git", 8834 - "reference": "172d807f9ef3fc3fbed8377cc57c20d389269271" 8847 + "reference": "ba020a321a95519303a3f09ec2824d34d601c388" 8835 8848 }, 8836 8849 "dist": { 8837 8850 "type": "zip", 8838 - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/172d807f9ef3fc3fbed8377cc57c20d389269271", 8839 - "reference": "172d807f9ef3fc3fbed8377cc57c20d389269271", 8851 + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ba020a321a95519303a3f09ec2824d34d601c388", 8852 + "reference": "ba020a321a95519303a3f09ec2824d34d601c388", 8840 8853 "shasum": "" 8841 8854 }, 8842 8855 "require": { ··· 8884 8897 "description": "Defines an object-oriented layer for the HTTP specification", 8885 8898 "homepage": "https://symfony.com", 8886 8899 "support": { 8887 - "source": "https://github.com/symfony/http-foundation/tree/v6.4.2" 8900 + "source": "https://github.com/symfony/http-foundation/tree/v6.4.14" 8888 8901 }, 8889 8902 "funding": [ 8890 8903 { ··· 8900 8913 "type": "tidelift" 8901 8914 } 8902 8915 ], 8903 - "time": "2023-12-27T22:16:42+00:00" 8916 + "time": "2024-11-05T16:39:55+00:00" 8904 8917 }, 8905 8918 { 8906 8919 "name": "symfony/http-kernel", 8907 - "version": "v6.3.1", 8920 + "version": "v6.4.14", 8908 8921 "source": { 8909 8922 "type": "git", 8910 8923 "url": "https://github.com/symfony/http-kernel.git", 8911 - "reference": "161e16fd2e35fb4881a43bc8b383dfd5be4ac374" 8924 + "reference": "8278a947d0369754a47b758a9e17b72cab970951" 8912 8925 }, 8913 8926 "dist": { 8914 8927 "type": "zip", 8915 - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/161e16fd2e35fb4881a43bc8b383dfd5be4ac374", 8916 - "reference": "161e16fd2e35fb4881a43bc8b383dfd5be4ac374", 8928 + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8278a947d0369754a47b758a9e17b72cab970951", 8929 + "reference": "8278a947d0369754a47b758a9e17b72cab970951", 8917 8930 "shasum": "" 8918 8931 }, 8919 8932 "require": { 8920 8933 "php": ">=8.1", 8921 8934 "psr/log": "^1|^2|^3", 8922 8935 "symfony/deprecation-contracts": "^2.5|^3", 8923 - "symfony/error-handler": "^6.3", 8924 - "symfony/event-dispatcher": "^5.4|^6.0", 8925 - "symfony/http-foundation": "^6.2.7", 8936 + "symfony/error-handler": "^6.4|^7.0", 8937 + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", 8938 + "symfony/http-foundation": "^6.4|^7.0", 8926 8939 "symfony/polyfill-ctype": "^1.8" 8927 8940 }, 8928 8941 "conflict": { ··· 8930 8943 "symfony/cache": "<5.4", 8931 8944 "symfony/config": "<6.1", 8932 8945 "symfony/console": "<5.4", 8933 - "symfony/dependency-injection": "<6.3", 8946 + "symfony/dependency-injection": "<6.4", 8934 8947 "symfony/doctrine-bridge": "<5.4", 8935 8948 "symfony/form": "<5.4", 8936 8949 "symfony/http-client": "<5.4", ··· 8940 8953 "symfony/translation": "<5.4", 8941 8954 "symfony/translation-contracts": "<2.5", 8942 8955 "symfony/twig-bridge": "<5.4", 8943 - "symfony/validator": "<5.4", 8956 + "symfony/validator": "<6.4", 8944 8957 "symfony/var-dumper": "<6.3", 8945 8958 "twig/twig": "<2.13" 8946 8959 }, ··· 8949 8962 }, 8950 8963 "require-dev": { 8951 8964 "psr/cache": "^1.0|^2.0|^3.0", 8952 - "symfony/browser-kit": "^5.4|^6.0", 8953 - "symfony/clock": "^6.2", 8954 - "symfony/config": "^6.1", 8955 - "symfony/console": "^5.4|^6.0", 8956 - "symfony/css-selector": "^5.4|^6.0", 8957 - "symfony/dependency-injection": "^6.3", 8958 - "symfony/dom-crawler": "^5.4|^6.0", 8959 - "symfony/expression-language": "^5.4|^6.0", 8960 - "symfony/finder": "^5.4|^6.0", 8965 + "symfony/browser-kit": "^5.4|^6.0|^7.0", 8966 + "symfony/clock": "^6.2|^7.0", 8967 + "symfony/config": "^6.1|^7.0", 8968 + "symfony/console": "^5.4|^6.0|^7.0", 8969 + "symfony/css-selector": "^5.4|^6.0|^7.0", 8970 + "symfony/dependency-injection": "^6.4|^7.0", 8971 + "symfony/dom-crawler": "^5.4|^6.0|^7.0", 8972 + "symfony/expression-language": "^5.4|^6.0|^7.0", 8973 + "symfony/finder": "^5.4|^6.0|^7.0", 8961 8974 "symfony/http-client-contracts": "^2.5|^3", 8962 - "symfony/process": "^5.4|^6.0", 8963 - "symfony/property-access": "^5.4.5|^6.0.5", 8964 - "symfony/routing": "^5.4|^6.0", 8965 - "symfony/serializer": "^6.3", 8966 - "symfony/stopwatch": "^5.4|^6.0", 8967 - "symfony/translation": "^5.4|^6.0", 8975 + "symfony/process": "^5.4|^6.0|^7.0", 8976 + "symfony/property-access": "^5.4.5|^6.0.5|^7.0", 8977 + "symfony/routing": "^5.4|^6.0|^7.0", 8978 + "symfony/serializer": "^6.4.4|^7.0.4", 8979 + "symfony/stopwatch": "^5.4|^6.0|^7.0", 8980 + "symfony/translation": "^5.4|^6.0|^7.0", 8968 8981 "symfony/translation-contracts": "^2.5|^3", 8969 - "symfony/uid": "^5.4|^6.0", 8970 - "symfony/validator": "^6.3", 8971 - "symfony/var-exporter": "^6.2", 8982 + "symfony/uid": "^5.4|^6.0|^7.0", 8983 + "symfony/validator": "^6.4|^7.0", 8984 + "symfony/var-dumper": "^5.4|^6.4|^7.0", 8985 + "symfony/var-exporter": "^6.2|^7.0", 8972 8986 "twig/twig": "^2.13|^3.0.4" 8973 8987 }, 8974 8988 "type": "library", ··· 8997 9011 "description": "Provides a structured process for converting a Request into a Response", 8998 9012 "homepage": "https://symfony.com", 8999 9013 "support": { 9000 - "source": "https://github.com/symfony/http-kernel/tree/v6.3.1" 9014 + "source": "https://github.com/symfony/http-kernel/tree/v6.4.14" 9001 9015 }, 9002 9016 "funding": [ 9003 9017 { ··· 9013 9027 "type": "tidelift" 9014 9028 } 9015 9029 ], 9016 - "time": "2023-06-26T06:07:32+00:00" 9030 + "time": "2024-11-06T09:45:21+00:00" 9017 9031 }, 9018 9032 { 9019 9033 "name": "symfony/mailer", 9020 - "version": "v6.3.0", 9034 + "version": "v6.4.13", 9021 9035 "source": { 9022 9036 "type": "git", 9023 9037 "url": "https://github.com/symfony/mailer.git", 9024 - "reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435" 9038 + "reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663" 9025 9039 }, 9026 9040 "dist": { 9027 9041 "type": "zip", 9028 - "url": "https://api.github.com/repos/symfony/mailer/zipball/7b03d9be1dea29bfec0a6c7b603f5072a4c97435", 9029 - "reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435", 9042 + "url": "https://api.github.com/repos/symfony/mailer/zipball/c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", 9043 + "reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", 9030 9044 "shasum": "" 9031 9045 }, 9032 9046 "require": { ··· 9034 9048 "php": ">=8.1", 9035 9049 "psr/event-dispatcher": "^1", 9036 9050 "psr/log": "^1|^2|^3", 9037 - "symfony/event-dispatcher": "^5.4|^6.0", 9038 - "symfony/mime": "^6.2", 9051 + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", 9052 + "symfony/mime": "^6.2|^7.0", 9039 9053 "symfony/service-contracts": "^2.5|^3" 9040 9054 }, 9041 9055 "conflict": { ··· 9046 9060 "symfony/twig-bridge": "<6.2.1" 9047 9061 }, 9048 9062 "require-dev": { 9049 - "symfony/console": "^5.4|^6.0", 9050 - "symfony/http-client": "^5.4|^6.0", 9051 - "symfony/messenger": "^6.2", 9052 - "symfony/twig-bridge": "^6.2" 9063 + "symfony/console": "^5.4|^6.0|^7.0", 9064 + "symfony/http-client": "^5.4|^6.0|^7.0", 9065 + "symfony/messenger": "^6.2|^7.0", 9066 + "symfony/twig-bridge": "^6.2|^7.0" 9053 9067 }, 9054 9068 "type": "library", 9055 9069 "autoload": { ··· 9077 9091 "description": "Helps sending emails", 9078 9092 "homepage": "https://symfony.com", 9079 9093 "support": { 9080 - "source": "https://github.com/symfony/mailer/tree/v6.3.0" 9094 + "source": "https://github.com/symfony/mailer/tree/v6.4.13" 9081 9095 }, 9082 9096 "funding": [ 9083 9097 { ··· 9093 9107 "type": "tidelift" 9094 9108 } 9095 9109 ], 9096 - "time": "2023-05-29T12:49:39+00:00" 9110 + "time": "2024-09-25T14:18:03+00:00" 9097 9111 }, 9098 9112 { 9099 9113 "name": "symfony/mime", 9100 - "version": "v6.4.0", 9114 + "version": "v6.4.13", 9101 9115 "source": { 9102 9116 "type": "git", 9103 9117 "url": "https://github.com/symfony/mime.git", 9104 - "reference": "ca4f58b2ef4baa8f6cecbeca2573f88cd577d205" 9118 + "reference": "1de1cf14d99b12c7ebbb850491ec6ae3ed468855" 9105 9119 }, 9106 9120 "dist": { 9107 9121 "type": "zip", 9108 - "url": "https://api.github.com/repos/symfony/mime/zipball/ca4f58b2ef4baa8f6cecbeca2573f88cd577d205", 9109 - "reference": "ca4f58b2ef4baa8f6cecbeca2573f88cd577d205", 9122 + "url": "https://api.github.com/repos/symfony/mime/zipball/1de1cf14d99b12c7ebbb850491ec6ae3ed468855", 9123 + "reference": "1de1cf14d99b12c7ebbb850491ec6ae3ed468855", 9110 9124 "shasum": "" 9111 9125 }, 9112 9126 "require": { ··· 9120 9134 "phpdocumentor/reflection-docblock": "<3.2.2", 9121 9135 "phpdocumentor/type-resolver": "<1.4.0", 9122 9136 "symfony/mailer": "<5.4", 9123 - "symfony/serializer": "<6.3.2" 9137 + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" 9124 9138 }, 9125 9139 "require-dev": { 9126 9140 "egulias/email-validator": "^2.1.10|^3.1|^4", 9127 9141 "league/html-to-markdown": "^5.0", 9128 9142 "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", 9129 9143 "symfony/dependency-injection": "^5.4|^6.0|^7.0", 9144 + "symfony/process": "^5.4|^6.4|^7.0", 9130 9145 "symfony/property-access": "^5.4|^6.0|^7.0", 9131 9146 "symfony/property-info": "^5.4|^6.0|^7.0", 9132 - "symfony/serializer": "^6.3.2|^7.0" 9147 + "symfony/serializer": "^6.4.3|^7.0.3" 9133 9148 }, 9134 9149 "type": "library", 9135 9150 "autoload": { ··· 9161 9176 "mime-type" 9162 9177 ], 9163 9178 "support": { 9164 - "source": "https://github.com/symfony/mime/tree/v6.4.0" 9179 + "source": "https://github.com/symfony/mime/tree/v6.4.13" 9165 9180 }, 9166 9181 "funding": [ 9167 9182 { ··· 9177 9192 "type": "tidelift" 9178 9193 } 9179 9194 ], 9180 - "time": "2023-10-17T11:49:05+00:00" 9195 + "time": "2024-10-25T15:07:50+00:00" 9181 9196 }, 9182 9197 { 9183 9198 "name": "symfony/options-resolver", ··· 9248 9263 }, 9249 9264 { 9250 9265 "name": "symfony/polyfill-ctype", 9251 - "version": "v1.27.0", 9266 + "version": "v1.31.0", 9252 9267 "source": { 9253 9268 "type": "git", 9254 9269 "url": "https://github.com/symfony/polyfill-ctype.git", 9255 - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" 9270 + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" 9256 9271 }, 9257 9272 "dist": { 9258 9273 "type": "zip", 9259 - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", 9260 - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", 9274 + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", 9275 + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", 9261 9276 "shasum": "" 9262 9277 }, 9263 9278 "require": { 9264 - "php": ">=7.1" 9279 + "php": ">=7.2" 9265 9280 }, 9266 9281 "provide": { 9267 9282 "ext-ctype": "*" ··· 9271 9286 }, 9272 9287 "type": "library", 9273 9288 "extra": { 9274 - "branch-alias": { 9275 - "dev-main": "1.27-dev" 9276 - }, 9277 9289 "thanks": { 9278 9290 "name": "symfony/polyfill", 9279 9291 "url": "https://github.com/symfony/polyfill" ··· 9310 9322 "portable" 9311 9323 ], 9312 9324 "support": { 9313 - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" 9325 + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" 9314 9326 }, 9315 9327 "funding": [ 9316 9328 { ··· 9326 9338 "type": "tidelift" 9327 9339 } 9328 9340 ], 9329 - "time": "2022-11-03T14:55:06+00:00" 9341 + "time": "2024-09-09T11:45:10+00:00" 9330 9342 }, 9331 9343 { 9332 9344 "name": "symfony/polyfill-intl-grapheme", 9333 - "version": "v1.27.0", 9345 + "version": "v1.31.0", 9334 9346 "source": { 9335 9347 "type": "git", 9336 9348 "url": "https://github.com/symfony/polyfill-intl-grapheme.git", 9337 - "reference": "511a08c03c1960e08a883f4cffcacd219b758354" 9349 + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" 9338 9350 }, 9339 9351 "dist": { 9340 9352 "type": "zip", 9341 - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", 9342 - "reference": "511a08c03c1960e08a883f4cffcacd219b758354", 9353 + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", 9354 + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", 9343 9355 "shasum": "" 9344 9356 }, 9345 9357 "require": { 9346 - "php": ">=7.1" 9358 + "php": ">=7.2" 9347 9359 }, 9348 9360 "suggest": { 9349 9361 "ext-intl": "For best performance" 9350 9362 }, 9351 9363 "type": "library", 9352 9364 "extra": { 9353 - "branch-alias": { 9354 - "dev-main": "1.27-dev" 9355 - }, 9356 9365 "thanks": { 9357 9366 "name": "symfony/polyfill", 9358 9367 "url": "https://github.com/symfony/polyfill" ··· 9391 9400 "shim" 9392 9401 ], 9393 9402 "support": { 9394 - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" 9403 + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" 9395 9404 }, 9396 9405 "funding": [ 9397 9406 { ··· 9407 9416 "type": "tidelift" 9408 9417 } 9409 9418 ], 9410 - "time": "2022-11-03T14:55:06+00:00" 9419 + "time": "2024-09-09T11:45:10+00:00" 9411 9420 }, 9412 9421 { 9413 9422 "name": "symfony/polyfill-intl-idn", 9414 - "version": "v1.28.0", 9423 + "version": "v1.31.0", 9415 9424 "source": { 9416 9425 "type": "git", 9417 9426 "url": "https://github.com/symfony/polyfill-intl-idn.git", 9418 - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" 9427 + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" 9419 9428 }, 9420 9429 "dist": { 9421 9430 "type": "zip", 9422 - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", 9423 - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", 9431 + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", 9432 + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", 9424 9433 "shasum": "" 9425 9434 }, 9426 9435 "require": { 9427 - "php": ">=7.1", 9428 - "symfony/polyfill-intl-normalizer": "^1.10", 9429 - "symfony/polyfill-php72": "^1.10" 9436 + "php": ">=7.2", 9437 + "symfony/polyfill-intl-normalizer": "^1.10" 9430 9438 }, 9431 9439 "suggest": { 9432 9440 "ext-intl": "For best performance" 9433 9441 }, 9434 9442 "type": "library", 9435 9443 "extra": { 9436 - "branch-alias": { 9437 - "dev-main": "1.28-dev" 9438 - }, 9439 9444 "thanks": { 9440 9445 "name": "symfony/polyfill", 9441 9446 "url": "https://github.com/symfony/polyfill" ··· 9478 9483 "shim" 9479 9484 ], 9480 9485 "support": { 9481 - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" 9486 + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" 9482 9487 }, 9483 9488 "funding": [ 9484 9489 { ··· 9494 9499 "type": "tidelift" 9495 9500 } 9496 9501 ], 9497 - "time": "2023-01-26T09:30:37+00:00" 9502 + "time": "2024-09-09T11:45:10+00:00" 9498 9503 }, 9499 9504 { 9500 9505 "name": "symfony/polyfill-intl-normalizer", 9501 - "version": "v1.28.0", 9506 + "version": "v1.31.0", 9502 9507 "source": { 9503 9508 "type": "git", 9504 9509 "url": "https://github.com/symfony/polyfill-intl-normalizer.git", 9505 - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" 9510 + "reference": "3833d7255cc303546435cb650316bff708a1c75c" 9506 9511 }, 9507 9512 "dist": { 9508 9513 "type": "zip", 9509 - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", 9510 - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", 9514 + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", 9515 + "reference": "3833d7255cc303546435cb650316bff708a1c75c", 9511 9516 "shasum": "" 9512 9517 }, 9513 9518 "require": { 9514 - "php": ">=7.1" 9519 + "php": ">=7.2" 9515 9520 }, 9516 9521 "suggest": { 9517 9522 "ext-intl": "For best performance" 9518 9523 }, 9519 9524 "type": "library", 9520 9525 "extra": { 9521 - "branch-alias": { 9522 - "dev-main": "1.28-dev" 9523 - }, 9524 9526 "thanks": { 9525 9527 "name": "symfony/polyfill", 9526 9528 "url": "https://github.com/symfony/polyfill" ··· 9562 9564 "shim" 9563 9565 ], 9564 9566 "support": { 9565 - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" 9567 + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" 9566 9568 }, 9567 9569 "funding": [ 9568 9570 { ··· 9578 9580 "type": "tidelift" 9579 9581 } 9580 9582 ], 9581 - "time": "2023-01-26T09:26:14+00:00" 9583 + "time": "2024-09-09T11:45:10+00:00" 9582 9584 }, 9583 9585 { 9584 9586 "name": "symfony/polyfill-mbstring", 9585 - "version": "v1.28.0", 9587 + "version": "v1.31.0", 9586 9588 "source": { 9587 9589 "type": "git", 9588 9590 "url": "https://github.com/symfony/polyfill-mbstring.git", 9589 - "reference": "42292d99c55abe617799667f454222c54c60e229" 9591 + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" 9590 9592 }, 9591 9593 "dist": { 9592 9594 "type": "zip", 9593 - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", 9594 - "reference": "42292d99c55abe617799667f454222c54c60e229", 9595 + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", 9596 + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", 9595 9597 "shasum": "" 9596 9598 }, 9597 9599 "require": { 9598 - "php": ">=7.1" 9600 + "php": ">=7.2" 9599 9601 }, 9600 9602 "provide": { 9601 9603 "ext-mbstring": "*" ··· 9605 9607 }, 9606 9608 "type": "library", 9607 9609 "extra": { 9608 - "branch-alias": { 9609 - "dev-main": "1.28-dev" 9610 - }, 9611 9610 "thanks": { 9612 9611 "name": "symfony/polyfill", 9613 9612 "url": "https://github.com/symfony/polyfill" ··· 9645 9644 "shim" 9646 9645 ], 9647 9646 "support": { 9648 - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" 9649 - }, 9650 - "funding": [ 9651 - { 9652 - "url": "https://symfony.com/sponsor", 9653 - "type": "custom" 9654 - }, 9655 - { 9656 - "url": "https://github.com/fabpot", 9657 - "type": "github" 9658 - }, 9659 - { 9660 - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 9661 - "type": "tidelift" 9662 - } 9663 - ], 9664 - "time": "2023-07-28T09:04:16+00:00" 9665 - }, 9666 - { 9667 - "name": "symfony/polyfill-php72", 9668 - "version": "v1.28.0", 9669 - "source": { 9670 - "type": "git", 9671 - "url": "https://github.com/symfony/polyfill-php72.git", 9672 - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" 9673 - }, 9674 - "dist": { 9675 - "type": "zip", 9676 - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", 9677 - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", 9678 - "shasum": "" 9679 - }, 9680 - "require": { 9681 - "php": ">=7.1" 9682 - }, 9683 - "type": "library", 9684 - "extra": { 9685 - "branch-alias": { 9686 - "dev-main": "1.28-dev" 9687 - }, 9688 - "thanks": { 9689 - "name": "symfony/polyfill", 9690 - "url": "https://github.com/symfony/polyfill" 9691 - } 9692 - }, 9693 - "autoload": { 9694 - "files": [ 9695 - "bootstrap.php" 9696 - ], 9697 - "psr-4": { 9698 - "Symfony\\Polyfill\\Php72\\": "" 9699 - } 9700 - }, 9701 - "notification-url": "https://packagist.org/downloads/", 9702 - "license": [ 9703 - "MIT" 9704 - ], 9705 - "authors": [ 9706 - { 9707 - "name": "Nicolas Grekas", 9708 - "email": "p@tchwork.com" 9709 - }, 9710 - { 9711 - "name": "Symfony Community", 9712 - "homepage": "https://symfony.com/contributors" 9713 - } 9714 - ], 9715 - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", 9716 - "homepage": "https://symfony.com", 9717 - "keywords": [ 9718 - "compatibility", 9719 - "polyfill", 9720 - "portable", 9721 - "shim" 9722 - ], 9723 - "support": { 9724 - "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" 9647 + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" 9725 9648 }, 9726 9649 "funding": [ 9727 9650 { ··· 9737 9660 "type": "tidelift" 9738 9661 } 9739 9662 ], 9740 - "time": "2023-01-26T09:26:14+00:00" 9663 + "time": "2024-09-09T11:45:10+00:00" 9741 9664 }, 9742 9665 { 9743 9666 "name": "symfony/polyfill-php80", 9744 - "version": "v1.28.0", 9667 + "version": "v1.31.0", 9745 9668 "source": { 9746 9669 "type": "git", 9747 9670 "url": "https://github.com/symfony/polyfill-php80.git", 9748 - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" 9671 + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" 9749 9672 }, 9750 9673 "dist": { 9751 9674 "type": "zip", 9752 - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", 9753 - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", 9675 + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", 9676 + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", 9754 9677 "shasum": "" 9755 9678 }, 9756 9679 "require": { 9757 - "php": ">=7.1" 9680 + "php": ">=7.2" 9758 9681 }, 9759 9682 "type": "library", 9760 9683 "extra": { 9761 - "branch-alias": { 9762 - "dev-main": "1.28-dev" 9763 - }, 9764 9684 "thanks": { 9765 9685 "name": "symfony/polyfill", 9766 9686 "url": "https://github.com/symfony/polyfill" ··· 9804 9724 "shim" 9805 9725 ], 9806 9726 "support": { 9807 - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" 9727 + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" 9808 9728 }, 9809 9729 "funding": [ 9810 9730 { ··· 9820 9740 "type": "tidelift" 9821 9741 } 9822 9742 ], 9823 - "time": "2023-01-26T09:26:14+00:00" 9743 + "time": "2024-09-09T11:45:10+00:00" 9824 9744 }, 9825 9745 { 9826 9746 "name": "symfony/polyfill-php83", 9827 - "version": "v1.28.0", 9747 + "version": "v1.31.0", 9828 9748 "source": { 9829 9749 "type": "git", 9830 9750 "url": "https://github.com/symfony/polyfill-php83.git", 9831 - "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11" 9751 + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" 9832 9752 }, 9833 9753 "dist": { 9834 9754 "type": "zip", 9835 - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", 9836 - "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", 9755 + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", 9756 + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", 9837 9757 "shasum": "" 9838 9758 }, 9839 9759 "require": { 9840 - "php": ">=7.1", 9841 - "symfony/polyfill-php80": "^1.14" 9760 + "php": ">=7.2" 9842 9761 }, 9843 9762 "type": "library", 9844 9763 "extra": { 9845 - "branch-alias": { 9846 - "dev-main": "1.28-dev" 9847 - }, 9848 9764 "thanks": { 9849 9765 "name": "symfony/polyfill", 9850 9766 "url": "https://github.com/symfony/polyfill" ··· 9884 9800 "shim" 9885 9801 ], 9886 9802 "support": { 9887 - "source": "https://github.com/symfony/polyfill-php83/tree/v1.28.0" 9803 + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" 9888 9804 }, 9889 9805 "funding": [ 9890 9806 { ··· 9900 9816 "type": "tidelift" 9901 9817 } 9902 9818 ], 9903 - "time": "2023-08-16T06:22:46+00:00" 9819 + "time": "2024-09-09T11:45:10+00:00" 9904 9820 }, 9905 9821 { 9906 9822 "name": "symfony/polyfill-uuid", 9907 - "version": "v1.27.0", 9823 + "version": "v1.31.0", 9908 9824 "source": { 9909 9825 "type": "git", 9910 9826 "url": "https://github.com/symfony/polyfill-uuid.git", 9911 - "reference": "f3cf1a645c2734236ed1e2e671e273eeb3586166" 9827 + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" 9912 9828 }, 9913 9829 "dist": { 9914 9830 "type": "zip", 9915 - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/f3cf1a645c2734236ed1e2e671e273eeb3586166", 9916 - "reference": "f3cf1a645c2734236ed1e2e671e273eeb3586166", 9831 + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", 9832 + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", 9917 9833 "shasum": "" 9918 9834 }, 9919 9835 "require": { 9920 - "php": ">=7.1" 9836 + "php": ">=7.2" 9921 9837 }, 9922 9838 "provide": { 9923 9839 "ext-uuid": "*" ··· 9927 9843 }, 9928 9844 "type": "library", 9929 9845 "extra": { 9930 - "branch-alias": { 9931 - "dev-main": "1.27-dev" 9932 - }, 9933 9846 "thanks": { 9934 9847 "name": "symfony/polyfill", 9935 9848 "url": "https://github.com/symfony/polyfill" ··· 9966 9879 "uuid" 9967 9880 ], 9968 9881 "support": { 9969 - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.27.0" 9882 + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" 9970 9883 }, 9971 9884 "funding": [ 9972 9885 { ··· 9982 9895 "type": "tidelift" 9983 9896 } 9984 9897 ], 9985 - "time": "2022-11-03T14:55:06+00:00" 9898 + "time": "2024-09-09T11:45:10+00:00" 9986 9899 }, 9987 9900 { 9988 9901 "name": "symfony/process", 9989 - "version": "v6.3.0", 9902 + "version": "v6.4.14", 9990 9903 "source": { 9991 9904 "type": "git", 9992 9905 "url": "https://github.com/symfony/process.git", 9993 - "reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628" 9906 + "reference": "25214adbb0996d18112548de20c281be9f27279f" 9994 9907 }, 9995 9908 "dist": { 9996 9909 "type": "zip", 9997 - "url": "https://api.github.com/repos/symfony/process/zipball/8741e3ed7fe2e91ec099e02446fb86667a0f1628", 9998 - "reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628", 9910 + "url": "https://api.github.com/repos/symfony/process/zipball/25214adbb0996d18112548de20c281be9f27279f", 9911 + "reference": "25214adbb0996d18112548de20c281be9f27279f", 9999 9912 "shasum": "" 10000 9913 }, 10001 9914 "require": { ··· 10027 9940 "description": "Executes commands in sub-processes", 10028 9941 "homepage": "https://symfony.com", 10029 9942 "support": { 10030 - "source": "https://github.com/symfony/process/tree/v6.3.0" 9943 + "source": "https://github.com/symfony/process/tree/v6.4.14" 10031 9944 }, 10032 9945 "funding": [ 10033 9946 { ··· 10043 9956 "type": "tidelift" 10044 9957 } 10045 9958 ], 10046 - "time": "2023-05-19T08:06:44+00:00" 9959 + "time": "2024-11-06T09:25:01+00:00" 10047 9960 }, 10048 9961 { 10049 9962 "name": "symfony/psr-http-message-bridge", ··· 10136 10049 }, 10137 10050 { 10138 10051 "name": "symfony/routing", 10139 - "version": "v6.3.1", 10052 + "version": "v6.4.13", 10140 10053 "source": { 10141 10054 "type": "git", 10142 10055 "url": "https://github.com/symfony/routing.git", 10143 - "reference": "d37ad1779c38b8eb71996d17dc13030dcb7f9cf5" 10056 + "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278" 10144 10057 }, 10145 10058 "dist": { 10146 10059 "type": "zip", 10147 - "url": "https://api.github.com/repos/symfony/routing/zipball/d37ad1779c38b8eb71996d17dc13030dcb7f9cf5", 10148 - "reference": "d37ad1779c38b8eb71996d17dc13030dcb7f9cf5", 10060 + "url": "https://api.github.com/repos/symfony/routing/zipball/640a74250d13f9c30d5ca045b6aaaabcc8215278", 10061 + "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278", 10149 10062 "shasum": "" 10150 10063 }, 10151 10064 "require": { 10152 - "php": ">=8.1" 10065 + "php": ">=8.1", 10066 + "symfony/deprecation-contracts": "^2.5|^3" 10153 10067 }, 10154 10068 "conflict": { 10155 10069 "doctrine/annotations": "<1.12", ··· 10160 10074 "require-dev": { 10161 10075 "doctrine/annotations": "^1.12|^2", 10162 10076 "psr/log": "^1|^2|^3", 10163 - "symfony/config": "^6.2", 10164 - "symfony/dependency-injection": "^5.4|^6.0", 10165 - "symfony/expression-language": "^5.4|^6.0", 10166 - "symfony/http-foundation": "^5.4|^6.0", 10167 - "symfony/yaml": "^5.4|^6.0" 10077 + "symfony/config": "^6.2|^7.0", 10078 + "symfony/dependency-injection": "^5.4|^6.0|^7.0", 10079 + "symfony/expression-language": "^5.4|^6.0|^7.0", 10080 + "symfony/http-foundation": "^5.4|^6.0|^7.0", 10081 + "symfony/yaml": "^5.4|^6.0|^7.0" 10168 10082 }, 10169 10083 "type": "library", 10170 10084 "autoload": { ··· 10198 10112 "url" 10199 10113 ], 10200 10114 "support": { 10201 - "source": "https://github.com/symfony/routing/tree/v6.3.1" 10115 + "source": "https://github.com/symfony/routing/tree/v6.4.13" 10202 10116 }, 10203 10117 "funding": [ 10204 10118 { ··· 10214 10128 "type": "tidelift" 10215 10129 } 10216 10130 ], 10217 - "time": "2023-06-05T15:30:22+00:00" 10131 + "time": "2024-10-01T08:30:56+00:00" 10218 10132 }, 10219 10133 { 10220 10134 "name": "symfony/service-contracts", 10221 - "version": "v3.4.1", 10135 + "version": "v3.5.0", 10222 10136 "source": { 10223 10137 "type": "git", 10224 10138 "url": "https://github.com/symfony/service-contracts.git", 10225 - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" 10139 + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" 10226 10140 }, 10227 10141 "dist": { 10228 10142 "type": "zip", 10229 - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", 10230 - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", 10143 + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", 10144 + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", 10231 10145 "shasum": "" 10232 10146 }, 10233 10147 "require": { 10234 10148 "php": ">=8.1", 10235 - "psr/container": "^1.1|^2.0" 10149 + "psr/container": "^1.1|^2.0", 10150 + "symfony/deprecation-contracts": "^2.5|^3" 10236 10151 }, 10237 10152 "conflict": { 10238 10153 "ext-psr": "<1.1|>=2" ··· 10240 10155 "type": "library", 10241 10156 "extra": { 10242 10157 "branch-alias": { 10243 - "dev-main": "3.4-dev" 10158 + "dev-main": "3.5-dev" 10244 10159 }, 10245 10160 "thanks": { 10246 10161 "name": "symfony/contracts", ··· 10280 10195 "standards" 10281 10196 ], 10282 10197 "support": { 10283 - "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" 10198 + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" 10284 10199 }, 10285 10200 "funding": [ 10286 10201 { ··· 10296 10211 "type": "tidelift" 10297 10212 } 10298 10213 ], 10299 - "time": "2023-12-26T14:02:43+00:00" 10214 + "time": "2024-04-18T09:32:20+00:00" 10300 10215 }, 10301 10216 { 10302 10217 "name": "symfony/string", 10303 - "version": "v6.3.0", 10218 + "version": "v7.1.6", 10304 10219 "source": { 10305 10220 "type": "git", 10306 10221 "url": "https://github.com/symfony/string.git", 10307 - "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f" 10222 + "reference": "61b72d66bf96c360a727ae6232df5ac83c71f626" 10308 10223 }, 10309 10224 "dist": { 10310 10225 "type": "zip", 10311 - "url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f", 10312 - "reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f", 10226 + "url": "https://api.github.com/repos/symfony/string/zipball/61b72d66bf96c360a727ae6232df5ac83c71f626", 10227 + "reference": "61b72d66bf96c360a727ae6232df5ac83c71f626", 10313 10228 "shasum": "" 10314 10229 }, 10315 10230 "require": { 10316 - "php": ">=8.1", 10231 + "php": ">=8.2", 10317 10232 "symfony/polyfill-ctype": "~1.8", 10318 10233 "symfony/polyfill-intl-grapheme": "~1.0", 10319 10234 "symfony/polyfill-intl-normalizer": "~1.0", ··· 10323 10238 "symfony/translation-contracts": "<2.5" 10324 10239 }, 10325 10240 "require-dev": { 10326 - "symfony/error-handler": "^5.4|^6.0", 10327 - "symfony/http-client": "^5.4|^6.0", 10328 - "symfony/intl": "^6.2", 10241 + "symfony/emoji": "^7.1", 10242 + "symfony/error-handler": "^6.4|^7.0", 10243 + "symfony/http-client": "^6.4|^7.0", 10244 + "symfony/intl": "^6.4|^7.0", 10329 10245 "symfony/translation-contracts": "^2.5|^3.0", 10330 - "symfony/var-exporter": "^5.4|^6.0" 10246 + "symfony/var-exporter": "^6.4|^7.0" 10331 10247 }, 10332 10248 "type": "library", 10333 10249 "autoload": { ··· 10366 10282 "utf8" 10367 10283 ], 10368 10284 "support": { 10369 - "source": "https://github.com/symfony/string/tree/v6.3.0" 10285 + "source": "https://github.com/symfony/string/tree/v7.1.6" 10370 10286 }, 10371 10287 "funding": [ 10372 10288 { ··· 10382 10298 "type": "tidelift" 10383 10299 } 10384 10300 ], 10385 - "time": "2023-03-21T21:06:29+00:00" 10301 + "time": "2024-09-25T14:20:29+00:00" 10386 10302 }, 10387 10303 { 10388 10304 "name": "symfony/translation", 10389 - "version": "v6.4.2", 10305 + "version": "v6.4.13", 10390 10306 "source": { 10391 10307 "type": "git", 10392 10308 "url": "https://github.com/symfony/translation.git", 10393 - "reference": "a2ab2ec1a462e53016de8e8d5e8912bfd62ea681" 10309 + "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66" 10394 10310 }, 10395 10311 "dist": { 10396 10312 "type": "zip", 10397 - "url": "https://api.github.com/repos/symfony/translation/zipball/a2ab2ec1a462e53016de8e8d5e8912bfd62ea681", 10398 - "reference": "a2ab2ec1a462e53016de8e8d5e8912bfd62ea681", 10313 + "url": "https://api.github.com/repos/symfony/translation/zipball/bee9bfabfa8b4045a66bf82520e492cddbaffa66", 10314 + "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66", 10399 10315 "shasum": "" 10400 10316 }, 10401 10317 "require": { ··· 10418 10334 "symfony/translation-implementation": "2.3|3.0" 10419 10335 }, 10420 10336 "require-dev": { 10421 - "nikic/php-parser": "^4.13", 10337 + "nikic/php-parser": "^4.18|^5.0", 10422 10338 "psr/log": "^1|^2|^3", 10423 10339 "symfony/config": "^5.4|^6.0|^7.0", 10424 10340 "symfony/console": "^5.4|^6.0|^7.0", ··· 10461 10377 "description": "Provides tools to internationalize your application", 10462 10378 "homepage": "https://symfony.com", 10463 10379 "support": { 10464 - "source": "https://github.com/symfony/translation/tree/v6.4.2" 10380 + "source": "https://github.com/symfony/translation/tree/v6.4.13" 10465 10381 }, 10466 10382 "funding": [ 10467 10383 { ··· 10477 10393 "type": "tidelift" 10478 10394 } 10479 10395 ], 10480 - "time": "2023-12-18T09:25:29+00:00" 10396 + "time": "2024-09-27T18:14:25+00:00" 10481 10397 }, 10482 10398 { 10483 10399 "name": "symfony/translation-contracts", 10484 - "version": "v3.4.1", 10400 + "version": "v3.5.0", 10485 10401 "source": { 10486 10402 "type": "git", 10487 10403 "url": "https://github.com/symfony/translation-contracts.git", 10488 - "reference": "06450585bf65e978026bda220cdebca3f867fde7" 10404 + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" 10489 10405 }, 10490 10406 "dist": { 10491 10407 "type": "zip", 10492 - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/06450585bf65e978026bda220cdebca3f867fde7", 10493 - "reference": "06450585bf65e978026bda220cdebca3f867fde7", 10408 + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", 10409 + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", 10494 10410 "shasum": "" 10495 10411 }, 10496 10412 "require": { ··· 10499 10415 "type": "library", 10500 10416 "extra": { 10501 10417 "branch-alias": { 10502 - "dev-main": "3.4-dev" 10418 + "dev-main": "3.5-dev" 10503 10419 }, 10504 10420 "thanks": { 10505 10421 "name": "symfony/contracts", ··· 10539 10455 "standards" 10540 10456 ], 10541 10457 "support": { 10542 - "source": "https://github.com/symfony/translation-contracts/tree/v3.4.1" 10458 + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" 10543 10459 }, 10544 10460 "funding": [ 10545 10461 { ··· 10555 10471 "type": "tidelift" 10556 10472 } 10557 10473 ], 10558 - "time": "2023-12-26T14:02:43+00:00" 10474 + "time": "2024-04-18T09:32:20+00:00" 10559 10475 }, 10560 10476 { 10561 10477 "name": "symfony/uid", 10562 - "version": "v6.3.0", 10478 + "version": "v6.4.13", 10563 10479 "source": { 10564 10480 "type": "git", 10565 10481 "url": "https://github.com/symfony/uid.git", 10566 - "reference": "01b0f20b1351d997711c56f1638f7a8c3061e384" 10482 + "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007" 10567 10483 }, 10568 10484 "dist": { 10569 10485 "type": "zip", 10570 - "url": "https://api.github.com/repos/symfony/uid/zipball/01b0f20b1351d997711c56f1638f7a8c3061e384", 10571 - "reference": "01b0f20b1351d997711c56f1638f7a8c3061e384", 10486 + "url": "https://api.github.com/repos/symfony/uid/zipball/18eb207f0436a993fffbdd811b5b8fa35fa5e007", 10487 + "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007", 10572 10488 "shasum": "" 10573 10489 }, 10574 10490 "require": { ··· 10576 10492 "symfony/polyfill-uuid": "^1.15" 10577 10493 }, 10578 10494 "require-dev": { 10579 - "symfony/console": "^5.4|^6.0" 10495 + "symfony/console": "^5.4|^6.0|^7.0" 10580 10496 }, 10581 10497 "type": "library", 10582 10498 "autoload": { ··· 10613 10529 "uuid" 10614 10530 ], 10615 10531 "support": { 10616 - "source": "https://github.com/symfony/uid/tree/v6.3.0" 10532 + "source": "https://github.com/symfony/uid/tree/v6.4.13" 10617 10533 }, 10618 10534 "funding": [ 10619 10535 { ··· 10629 10545 "type": "tidelift" 10630 10546 } 10631 10547 ], 10632 - "time": "2023-04-08T07:25:02+00:00" 10548 + "time": "2024-09-25T14:18:03+00:00" 10633 10549 }, 10634 10550 { 10635 10551 "name": "symfony/var-dumper", 10636 - "version": "v6.3.1", 10552 + "version": "v6.4.14", 10637 10553 "source": { 10638 10554 "type": "git", 10639 10555 "url": "https://github.com/symfony/var-dumper.git", 10640 - "reference": "c81268d6960ddb47af17391a27d222bd58cf0515" 10556 + "reference": "93c09246038178717a9c14b809ea8151ffcf7091" 10641 10557 }, 10642 10558 "dist": { 10643 10559 "type": "zip", 10644 - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c81268d6960ddb47af17391a27d222bd58cf0515", 10645 - "reference": "c81268d6960ddb47af17391a27d222bd58cf0515", 10560 + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/93c09246038178717a9c14b809ea8151ffcf7091", 10561 + "reference": "93c09246038178717a9c14b809ea8151ffcf7091", 10646 10562 "shasum": "" 10647 10563 }, 10648 10564 "require": { 10649 10565 "php": ">=8.1", 10566 + "symfony/deprecation-contracts": "^2.5|^3", 10650 10567 "symfony/polyfill-mbstring": "~1.0" 10651 10568 }, 10652 10569 "conflict": { ··· 10654 10571 }, 10655 10572 "require-dev": { 10656 10573 "ext-iconv": "*", 10657 - "symfony/console": "^5.4|^6.0", 10658 - "symfony/process": "^5.4|^6.0", 10659 - "symfony/uid": "^5.4|^6.0", 10574 + "symfony/console": "^5.4|^6.0|^7.0", 10575 + "symfony/error-handler": "^6.3|^7.0", 10576 + "symfony/http-kernel": "^5.4|^6.0|^7.0", 10577 + "symfony/process": "^5.4|^6.0|^7.0", 10578 + "symfony/uid": "^5.4|^6.0|^7.0", 10660 10579 "twig/twig": "^2.13|^3.0.4" 10661 10580 }, 10662 10581 "bin": [ ··· 10695 10614 "dump" 10696 10615 ], 10697 10616 "support": { 10698 - "source": "https://github.com/symfony/var-dumper/tree/v6.3.1" 10617 + "source": "https://github.com/symfony/var-dumper/tree/v6.4.14" 10699 10618 }, 10700 10619 "funding": [ 10701 10620 { ··· 10711 10630 "type": "tidelift" 10712 10631 } 10713 10632 ], 10714 - "time": "2023-06-21T12:08:28+00:00" 10633 + "time": "2024-11-05T15:34:40+00:00" 10715 10634 }, 10716 10635 { 10717 10636 "name": "symfony/var-exporter", ··· 10987 10906 }, 10988 10907 { 10989 10908 "name": "tijsverkoyen/css-to-inline-styles", 10990 - "version": "2.2.6", 10909 + "version": "v2.2.7", 10991 10910 "source": { 10992 10911 "type": "git", 10993 10912 "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", 10994 - "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c" 10913 + "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb" 10995 10914 }, 10996 10915 "dist": { 10997 10916 "type": "zip", 10998 - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/c42125b83a4fa63b187fdf29f9c93cb7733da30c", 10999 - "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c", 10917 + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/83ee6f38df0a63106a9e4536e3060458b74ccedb", 10918 + "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb", 11000 10919 "shasum": "" 11001 10920 }, 11002 10921 "require": { 11003 10922 "ext-dom": "*", 11004 10923 "ext-libxml": "*", 11005 10924 "php": "^5.5 || ^7.0 || ^8.0", 11006 - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" 10925 + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" 11007 10926 }, 11008 10927 "require-dev": { 11009 10928 "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" ··· 11034 10953 "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", 11035 10954 "support": { 11036 10955 "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", 11037 - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.6" 10956 + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.2.7" 11038 10957 }, 11039 - "time": "2023-01-03T09:29:04+00:00" 10958 + "time": "2023-12-08T13:03:43+00:00" 11040 10959 }, 11041 10960 { 11042 10961 "name": "vlucas/phpdotenv", 11043 - "version": "v5.5.0", 10962 + "version": "v5.6.1", 11044 10963 "source": { 11045 10964 "type": "git", 11046 10965 "url": "https://github.com/vlucas/phpdotenv.git", 11047 - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7" 10966 + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" 11048 10967 }, 11049 10968 "dist": { 11050 10969 "type": "zip", 11051 - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", 11052 - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", 10970 + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", 10971 + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", 11053 10972 "shasum": "" 11054 10973 }, 11055 10974 "require": { 11056 10975 "ext-pcre": "*", 11057 - "graham-campbell/result-type": "^1.0.2", 11058 - "php": "^7.1.3 || ^8.0", 11059 - "phpoption/phpoption": "^1.8", 11060 - "symfony/polyfill-ctype": "^1.23", 11061 - "symfony/polyfill-mbstring": "^1.23.1", 11062 - "symfony/polyfill-php80": "^1.23.1" 10976 + "graham-campbell/result-type": "^1.1.3", 10977 + "php": "^7.2.5 || ^8.0", 10978 + "phpoption/phpoption": "^1.9.3", 10979 + "symfony/polyfill-ctype": "^1.24", 10980 + "symfony/polyfill-mbstring": "^1.24", 10981 + "symfony/polyfill-php80": "^1.24" 11063 10982 }, 11064 10983 "require-dev": { 11065 - "bamarni/composer-bin-plugin": "^1.4.1", 10984 + "bamarni/composer-bin-plugin": "^1.8.2", 11066 10985 "ext-filter": "*", 11067 - "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25" 10986 + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" 11068 10987 }, 11069 10988 "suggest": { 11070 10989 "ext-filter": "Required to use the boolean validator." ··· 11073 10992 "extra": { 11074 10993 "bamarni-bin": { 11075 10994 "bin-links": true, 11076 - "forward-command": true 10995 + "forward-command": false 11077 10996 }, 11078 10997 "branch-alias": { 11079 - "dev-master": "5.5-dev" 10998 + "dev-master": "5.6-dev" 11080 10999 } 11081 11000 }, 11082 11001 "autoload": { ··· 11108 11027 ], 11109 11028 "support": { 11110 11029 "issues": "https://github.com/vlucas/phpdotenv/issues", 11111 - "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0" 11030 + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" 11112 11031 }, 11113 11032 "funding": [ 11114 11033 { ··· 11120 11039 "type": "tidelift" 11121 11040 } 11122 11041 ], 11123 - "time": "2022-10-16T01:01:54+00:00" 11042 + "time": "2024-07-20T21:52:34+00:00" 11124 11043 }, 11125 11044 { 11126 11045 "name": "voku/portable-ascii",
+1 -11
config/osu.php
··· 152 152 ], 153 153 'multiplayer' => [ 154 154 'max_attempts_limit' => get_int(env('MULTIPLAYER_MAX_ATTEMPTS_LIMIT')) ?? 128, 155 + 'room_close_grace_period_minutes' => get_int(env('MULTIPLAYER_ROOM_CLOSE_GRACE_PERIOD_MINUTES')) ?? 5, 155 156 ], 156 157 'notification' => [ 157 158 'endpoint' => presence(env('NOTIFICATION_ENDPOINT'), '/home/notifications/feed'), ··· 205 206 ], 206 207 'twitch_client_id' => presence(env('TWITCH_CLIENT_ID')), 207 208 'twitch_client_secret' => presence(env('TWITCH_CLIENT_SECRET')), 208 - 'tournament_banner' => [ 209 - 'current' => [ 210 - 'id' => get_int(env('TOURNAMENT_BANNER_CURRENT_ID')), 211 - 'prefix' => env('TOURNAMENT_BANNER_CURRENT_PREFIX'), 212 - ], 213 - 'previous' => [ 214 - 'id' => get_int(env('TOURNAMENT_BANNER_PREVIOUS_ID')), 215 - 'prefix' => env('TOURNAMENT_BANNER_PREVIOUS_PREFIX'), 216 - 'winner_id' => env('TOURNAMENT_BANNER_PREVIOUS_WINNER_ID'), 217 - ], 218 - ], 219 209 'urls' => [ 220 210 'base' => 'https://osu.ppy.sh', 221 211 'bounty-form' => env('OS_BOUNTY_URL'),
+5
database/factories/CountryFactory.php
··· 13 13 { 14 14 protected $model = Country::class; 15 15 16 + public function configure(): static 17 + { 18 + return $this->afterCreating(fn () => app('countries')->resetMemoized()); 19 + } 20 + 16 21 public function definition(): array 17 22 { 18 23 return [
+30
database/migrations/2024_11_06_074123_create_tournament_banners.php
··· 1 + <?php 2 + 3 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4 + // See the LICENCE file in the repository root for full licence text. 5 + 6 + declare(strict_types=1); 7 + 8 + use Illuminate\Database\Migrations\Migration; 9 + use Illuminate\Database\Schema\Blueprint; 10 + use Illuminate\Support\Facades\Schema; 11 + 12 + return new class extends Migration 13 + { 14 + public function up(): void 15 + { 16 + Schema::create('tournament_banners', function (Blueprint $table) { 17 + $table->unsignedMediumInteger('tournament_id')->primary(); 18 + $table->boolean('is_active')->default(false); 19 + $table->char('winner_country_acronym', 2)->nullable(true); 20 + $table->string('banner_url_prefix'); 21 + $table->timestampTz('created_at')->useCurrent(); 22 + $table->timestampTz('updated_at')->useCurrent(); 23 + }); 24 + } 25 + 26 + public function down(): void 27 + { 28 + Schema::dropIfExists('tournament_banners'); 29 + } 30 + };
+55
database/migrations/2024_11_19_130731_create_beatmap_versioning_tables.php
··· 1 + <?php 2 + 3 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4 + // See the LICENCE file in the repository root for full licence text. 5 + 6 + use Illuminate\Database\Migrations\Migration; 7 + use Illuminate\Database\Schema\Blueprint; 8 + 9 + return new class extends Migration 10 + { 11 + /** 12 + * Run the migrations. 13 + */ 14 + public function up(): void 15 + { 16 + // raw statement used as laravel syntax doesn't support a fixed size BINARY column 17 + DB::statement('CREATE TABLE `beatmapset_files` ( 18 + `file_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 19 + `sha2_hash` BINARY(32) NOT NULL, 20 + `file_size` INT UNSIGNED NOT NULL, 21 + 22 + UNIQUE (`sha2_hash`) 23 + )'); 24 + 25 + Schema::create('beatmapset_versions', function (Blueprint $table) { 26 + $table->bigIncrements('version_id'); 27 + $table->mediumInteger('beatmapset_id')->unsigned(); 28 + $table->timestamp('created_at')->useCurrent(); 29 + $table->bigInteger('previous_version_id')->unsigned()->nullable(); 30 + 31 + $table->index('beatmapset_id'); 32 + $table->index('previous_version_id'); 33 + }); 34 + 35 + Schema::create('beatmapset_version_files', function (Blueprint $table) { 36 + $table->bigInteger('file_id')->unsigned(); 37 + $table->bigInteger('version_id')->unsigned(); 38 + $table->string('filename', length: 500); 39 + 40 + $table->primary(['file_id', 'version_id']); 41 + $table->index('file_id'); 42 + $table->index('version_id'); 43 + }); 44 + } 45 + 46 + /** 47 + * Reverse the migrations. 48 + */ 49 + public function down(): void 50 + { 51 + Schema::dropIfExists('beatmapset_version_files'); 52 + Schema::dropIfExists('beatmapset_versions'); 53 + Schema::dropIfExists('beatmapset_files'); 54 + } 55 + };
+33
database/migrations/2024_11_22_092704_add_status_to_multiplayer_rooms.php
··· 1 + <?php 2 + 3 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4 + // See the LICENCE file in the repository root for full licence text. 5 + 6 + declare(strict_types=1); 7 + 8 + use Illuminate\Database\Migrations\Migration; 9 + use Illuminate\Database\Schema\Blueprint; 10 + use Illuminate\Support\Facades\Schema; 11 + 12 + return new class extends Migration 13 + { 14 + /** 15 + * Run the migrations. 16 + */ 17 + public function up(): void 18 + { 19 + Schema::table('multiplayer_rooms', function (Blueprint $table) { 20 + $table->enum('status', ['idle', 'playing'])->default('idle'); 21 + }); 22 + } 23 + 24 + /** 25 + * Reverse the migrations. 26 + */ 27 + public function down(): void 28 + { 29 + Schema::table('multiplayer_rooms', function (Blueprint $table) { 30 + $table->dropColumn('status'); 31 + }); 32 + } 33 + };
+37 -3
database/mods.json
··· 287 287 } 288 288 ], 289 289 "IncompatibleMods": [ 290 - "BL" 290 + "BL", 291 + "BM" 291 292 ], 292 293 "RequiresConfiguration": false, 293 294 "UserPlayable": true, ··· 1016 1017 "Description": "The combo count at which the cursor becomes completely hidden" 1017 1018 } 1018 1019 ], 1019 - "IncompatibleMods": [], 1020 + "IncompatibleMods": [ 1021 + "BM" 1022 + ], 1020 1023 "RequiresConfiguration": false, 1021 1024 "UserPlayable": true, 1022 1025 "ValidForMultiplayer": true, ··· 1204 1207 "AlwaysValidForSubmission": false 1205 1208 }, 1206 1209 { 1210 + "Acronym": "BM", 1211 + "Name": "Bloom", 1212 + "Description": "The cursor blooms into.. a larger cursor!", 1213 + "Type": "Fun", 1214 + "Settings": [ 1215 + { 1216 + "Name": "max_size_combo_count", 1217 + "Type": "number", 1218 + "Label": "Max size at combo", 1219 + "Description": "The combo count at which the cursor reaches its maximum size" 1220 + }, 1221 + { 1222 + "Name": "max_cursor_size", 1223 + "Type": "number", 1224 + "Label": "Final size multiplier", 1225 + "Description": "The multiplier applied to cursor size when combo reaches maximum" 1226 + } 1227 + ], 1228 + "IncompatibleMods": [ 1229 + "FL", 1230 + "NS", 1231 + "TD" 1232 + ], 1233 + "RequiresConfiguration": false, 1234 + "UserPlayable": true, 1235 + "ValidForMultiplayer": true, 1236 + "ValidForMultiplayerAsFreeMod": true, 1237 + "AlwaysValidForSubmission": false 1238 + }, 1239 + { 1207 1240 "Acronym": "TD", 1208 1241 "Name": "Touch Device", 1209 1242 "Description": "Automatically applied to plays on devices with a touchscreen.", ··· 1212 1245 "IncompatibleMods": [ 1213 1246 "AT", 1214 1247 "CN", 1215 - "AP" 1248 + "AP", 1249 + "BM" 1216 1250 ], 1217 1251 "RequiresConfiguration": false, 1218 1252 "UserPlayable": true,
+2 -3
docker-compose.yml
··· 1 1 x-env: &x-env 2 2 APP_KEY: "${APP_KEY}" 3 - BEATMAPS_DIFFICULTY_CACHE_SERVER_URL: http://beatmap-difficulty-lookup-cache 3 + BEATMAPS_DIFFICULTY_CACHE_SERVER_URL: http://beatmap-difficulty-lookup-cache:8080 4 4 BROADCAST_DRIVER: redis 5 5 DB_CONNECTION_STRING: Server=db;Database=osu;Uid=osuweb; 6 6 DB_HOST: db ··· 69 69 beatmap-difficulty-lookup-cache: 70 70 image: pppy/osu-beatmap-difficulty-lookup-cache 71 71 ports: 72 - - "${BEATMAPS_DIFFICULTY_CACHE_EXTERNAL_PORT:-127.0.0.1:5001}:80" 72 + - "${BEATMAPS_DIFFICULTY_CACHE_EXTERNAL_PORT:-127.0.0.1:5001}:8080" 73 73 74 74 notification-server: 75 75 image: pppy/osu-notification-server ··· 110 110 MYSQL_ALLOW_EMPTY_PASSWORD: "yes" 111 111 ports: 112 112 - "${MYSQL_EXTERNAL_PORT:-127.0.0.1:3306}:3306" 113 - command: --default-authentication-plugin=mysql_native_password 114 113 healthcheck: 115 114 # important to use 127.0.0.1 instead of localhost as mysql starts twice. 116 115 # the first time it listens on sockets but isn't actually ready
+4 -75
docker/development/entrypoint.sh
··· 1 1 #!/bin/sh 2 2 3 - set -e 4 - set -u 5 - 6 - export CHROME_BIN=/usr/bin/chromium 7 - export DUSK_WEBDRIVER_BIN=/usr/bin/chromedriver 8 - export YARN_CACHE_FOLDER=/app/.docker/.yarn 9 - export COMPOSER_HOME=/app/.docker/.composer 10 - 11 - command=octane 12 - if [ "$#" -gt 0 ]; then 13 - command="$1" 14 - shift 15 - fi 16 - 17 - uid="$(stat -c "%u" /app)" 18 - gid="$(stat -c "%g" /app)" 3 + uid=$(stat -c "%u" .) 4 + gid=$(stat -c "%g" .) 19 5 20 6 if [ "$uid" != 0 ]; then 21 7 usermod -u "$uid" -o osuweb > /dev/null 22 8 groupmod -g "$gid" -o osuweb > /dev/null 23 9 fi 24 10 25 - usermod -d /app/.docker osuweb > /dev/null 26 - chown -f "${uid}:${gid}" .docker/js-build/assets .docker/js-build/builds || true 27 - 28 - # helper functions 29 - _rexec() { 30 - exec gosu osuweb "$@" 31 - } 32 - 33 - _run() { 34 - gosu osuweb "$@" 35 - } 36 - 37 - # commands 38 - _job() { 39 - _rexec php /app/artisan queue:listen --queue=notification,default,beatmap_high,beatmap_default,store-notifications --tries=3 --timeout=1000 40 - } 11 + chown -f "${uid}:${gid}" .docker/js-build/assets .docker/js-build/builds 41 12 42 - _migrate() { 43 - _run php /app/artisan db:create 44 - _rexec php /app/artisan migrate:fresh-or-run 45 - } 46 - 47 - _octane() { 48 - _rexec /app/artisan octane:start --host=0.0.0.0 "$@" 49 - } 50 - 51 - _schedule() { 52 - _rexec php /app/artisan schedule:work 53 - } 54 - 55 - _test() { 56 - command=phpunit 57 - if [ "$#" -gt 0 ]; then 58 - command="$1" 59 - shift 60 - fi 61 - 62 - case "$command" in 63 - browser) _test_browser "$@";; 64 - js) _rexec yarn karma start --single-run --browsers ChromeHeadless "$@";; 65 - phpunit) _rexec ./bin/phpunit.sh "$@";; 66 - esac 67 - } 68 - 69 - _test_browser() { 70 - export APP_ENV=dusk.local 71 - _rexec php /app/artisan dusk "$@" 72 - } 73 - 74 - 75 - _watch() { 76 - _run yarn --network-timeout 100000 77 - _rexec yarn watch 78 - } 79 - 80 - case "$command" in 81 - artisan) _rexec php /app/artisan "$@";; 82 - job|migrate|octane|schedule|test|watch) "_$command" "$@";; 83 - *) _rexec "$command" "$@";; 84 - esac 13 + exec gosu osuweb ./docker/development/run.sh "$@"
+2
docker/development/prepare.sh
··· 29 29 grep ^GITHUB_TOKEN= .env || echo "GITHUB_TOKEN=${GITHUB_TOKEN}" >> .env 30 30 fi 31 31 32 + docker compose build 33 + 32 34 _run yarn --network-timeout 100000 --frozen-lockfile 33 35 34 36 _run composer install
+59
docker/development/run.sh
··· 1 + #!/bin/sh 2 + 3 + export CHROME_BIN=/usr/bin/chromium 4 + export DUSK_WEBDRIVER_BIN=/usr/bin/chromedriver 5 + 6 + command=octane 7 + if [ "$#" -gt 0 ]; then 8 + command="$1" 9 + shift 10 + fi 11 + 12 + # commands 13 + _job() { 14 + exec ./artisan queue:listen --queue=notification,default,beatmap_high,beatmap_default,store-notifications --tries=3 --timeout=1000 15 + } 16 + 17 + _migrate() { 18 + ./artisan db:create 19 + exec ./artisan migrate:fresh-or-run 20 + } 21 + 22 + _octane() { 23 + exec ./artisan octane:start --host=0.0.0.0 "$@" 24 + } 25 + 26 + _schedule() { 27 + exec ./artisan schedule:work 28 + } 29 + 30 + _test() { 31 + command=phpunit 32 + if [ "$#" -gt 0 ]; then 33 + command="$1" 34 + shift 35 + fi 36 + 37 + case "$command" in 38 + browser) _test_browser "$@";; 39 + js) exec yarn karma start --single-run --browsers ChromeHeadless "$@";; 40 + phpunit) exec ./bin/phpunit.sh "$@";; 41 + esac 42 + } 43 + 44 + _test_browser() { 45 + export APP_ENV=dusk.local 46 + exec ./artisan dusk "$@" 47 + } 48 + 49 + 50 + _watch() { 51 + yarn --network-timeout 100000 52 + exec yarn watch 53 + } 54 + 55 + case "$command" in 56 + artisan) exec ./artisan "$@";; 57 + job|migrate|octane|schedule|test|watch) "_$command" "$@";; 58 + *) exec "$command" "$@";; 59 + esac
+5 -3
package.json
··· 13 13 "dependencies": { 14 14 "@discordapp/twemoji": "^14.0.2", 15 15 "@fortawesome/fontawesome-free": "^5.6.3", 16 + "@hotwired/turbo": "^8.0.12", 16 17 "@types/autosize": "^4.0.1", 17 18 "@types/bootstrap": "^3.3.0", 18 19 "@types/cloudflare-turnstile": "^0.1.5", 19 20 "@types/d3": "^7.1.0", 21 + "@types/hotwired__turbo": "^8.0.2", 20 22 "@types/is-hotkey": "^0.1.1", 21 23 "@types/jasmine": "^3.3.13", 22 24 "@types/jquery": "^3.3.0", ··· 34 36 "blueimp-file-upload": "^9.11.2", 35 37 "bootstrap": "^3.3.6", 36 38 "chokidar": "^3.5.2", 37 - "clean-webpack-plugin": "^3.0.0", 38 39 "clipboard-polyfill": "^2.3.0", 39 40 "coffee-loader": "^0.9.0", 40 41 "coffeescript": "^1.12.6", ··· 55 56 "jquery": "^3.5.0", 56 57 "jquery-ui": "^1.13.2", 57 58 "jquery-ui-touch-punch": "^0.2.3", 58 - "jquery-ujs": "^1.2.2", 59 + "jquery-ujs": "^1.2.3", 59 60 "jquery.scrollto": "^2.1.2", 60 61 "lang.js": "^1.1.14", 61 62 "less": "^3.9.0", ··· 90 91 "timeago": "^1.5.0", 91 92 "ts-loader": "^9.4.4", 92 93 "tsconfig-paths-webpack-plugin": "^3.2.0", 93 - "turbolinks": "^5.1.1", 94 94 "typescript": "^5.2.2", 95 95 "unified": "^10.1.2", 96 + "uuid": "^11.0.3", 96 97 "watchpack": "^2.4.0", 97 98 "webpack": "^5.94.0", 98 99 "webpack-cli": "^5.1.4", ··· 103 104 "devDependencies": { 104 105 "@typescript-eslint/eslint-plugin": "^6.6.0", 105 106 "@typescript-eslint/parser": "^6.6.0", 107 + "clean-webpack-plugin": "^4.0.0", 106 108 "eslint": "^7.15.0", 107 109 "eslint-plugin-import": "^2.22.1", 108 110 "eslint-plugin-jsdoc": "^30.7.8",
+1 -1
resources/css/bem-index.less
··· 390 390 @import "bem/tournament-list"; 391 391 @import "bem/tournament-list-item"; 392 392 @import "bem/track-cover-preview"; 393 - @import "bem/turbolinks-progress-bar"; 393 + @import "bem/turbo-progress-bar"; 394 394 @import "bem/update-streams-v2"; 395 395 @import "bem/user-action-button"; 396 396 @import "bem/user-card";
+29 -23
resources/css/bem/forum-item-stripe.less
··· 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 4 .forum-item-stripe { 5 + --width: 7px; 6 + --width-desktop: 9px; 7 + --arrow-opacity: 0; 5 8 position: absolute; 6 - top: 0; 7 - left: 0; 8 - width: 10px; 9 - padding-right: 5px; 10 - height: 100%; 11 - overflow: hidden; 9 + inset: 0 auto 0 0; 10 + padding-right: @border-radius-base; 11 + width: var(--width); 12 12 .center-content(); 13 - color: transparent; 14 13 transition: @forum-item-animate; 14 + background-color: inherit; 15 15 16 16 &::after { 17 17 content: ""; 18 - .full-size(); 18 + position: absolute; 19 + inset: 0 0 0 auto; 20 + width: @border-radius-base; 19 21 border-radius: @border-radius-base 0 0 @border-radius-base; 20 - background-color: var(--forum-item-background-color); 21 - top: 0; 22 - will-change: transform; 23 - transition: @forum-item-animate; 24 - left: 3px; 25 - 26 - @media @desktop { 27 - left: 5px; 28 - } 22 + background-color: inherit; 29 23 } 30 24 31 25 &::before { ··· 37 31 38 32 .forum-item:hover &, 39 33 .forum-topic-entry:hover & { 34 + --width-desktop: 24px; 35 + --arrow-opacity: 1; 36 + } 37 + 38 + @media @desktop { 39 + width: var(--width-desktop); 40 + } 41 + 42 + &__arrow { 43 + .fas(); 40 44 color: var(--forum-item-background-color-hover); 41 - width: 25px; 45 + position: relative; 46 + opacity: var(--arrow-opacity); 47 + display: none; 42 48 43 - &::after { 44 - background-color: var(--forum-item-background-color-hover); 49 + &::before { 50 + content: @fa-var-angle-right; 51 + } 45 52 46 - @media @desktop { 47 - transform: translateX(15px); 48 - } 53 + @media @desktop { 54 + display: block; 49 55 } 50 56 } 51 57 }
+1
resources/css/bem/forum-user-icon.less
··· 7 7 width: 0.6em; 8 8 display: inline-block; 9 9 border-radius: 10000px; 10 + margin-right: 2px; 10 11 }
+5
resources/css/bem/input-container.less
··· 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 4 .input-container { 5 + @top: input-container; 6 + 5 7 --label-font-size: @font-size--normal; 6 8 --label-line-height: 1.25; 7 9 --label-height: calc( ··· 16 18 --input-border-hover-colour: hsl(var(--hsl-l3)); 17 19 --input-border-focus-colour: hsl(var(--hsl-l1)); 18 20 --input-border-error-colour: hsl(var(--hsl-red-2)); 21 + --input-border-error-focus-colour: hsl(var(--hsl-red-3)); 19 22 --input-padding: var(--label-height) var(--input-padding-right) 20 23 var(--input-padding-base) var(--input-padding-base); 21 24 --input-padding-base: 10px; ··· 52 55 53 56 &--error { 54 57 --input-border-colour: var(--input-border-error-colour); 58 + --input-border-focus-colour: var(--input-border-error-focus-colour); 59 + --input-border-hover-colour: var(--input-border-error-focus-colour); 55 60 } 56 61 57 62 &--fill {
+1 -1
resources/css/bem/turbolinks-progress-bar.less resources/css/bem/turbo-progress-bar.less
··· 1 1 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 - .turbolinks-progress-bar { 4 + .turbo-progress-bar { 5 5 background-color: @yellow; 6 6 }
+4 -15
resources/js/app-deps.ts
··· 3 3 4 4 import CurrentUserJson from 'interfaces/current-user-json'; 5 5 6 + import 'setup-turbo'; 7 + 6 8 // import jquery + plugins 7 - import * as $ from 'jquery'; 9 + import 'setup-jquery'; 10 + // imported separately as it requires window jquery (setup by the import above) 8 11 import 'jquery-ujs'; 9 - import 'bootstrap'; 10 - import 'timeago/jquery.timeago.js'; 11 - import 'qtip2/dist/jquery.qtip.js'; 12 - import 'jquery.scrollto/jquery.scrollTo.js'; 13 - import 'jquery-ui/ui/data.js'; 14 - import 'jquery-ui/ui/widgets/slider.js'; 15 - import 'jquery-ui/ui/widgets/sortable.js'; 16 - import 'jquery-ui-touch-punch'; 17 - import 'blueimp-file-upload/js/jquery.fileupload.js'; 18 12 19 13 import { patchPluralHandler } from 'lang-overrides'; 20 14 import Lang from 'lang.js'; 21 15 import { configure as mobxConfigure } from 'mobx'; 22 16 import * as moment from 'moment'; 23 - import Turbolinks from 'turbolinks'; 24 17 import { popup } from 'utils/popup'; 25 18 import { reloadPage } from 'utils/turbolinks'; 26 19 ··· 67 60 moment: any; 68 61 popup: typeof popup; 69 62 reloadPage: typeof reloadPage; 70 - Turbolinks: Turbolinks; 71 63 } 72 64 } 73 65 74 - window.$ = $; 75 - window.jQuery = $; 76 66 window.LangMessages ??= {}; 77 67 window.Lang = patchPluralHandler(new Lang({ 78 68 fallback: window.fallbackLocale, ··· 82 72 window.moment = moment; 83 73 window.popup = popup; 84 74 window.reloadPage = reloadPage; 85 - window.Turbolinks = Turbolinks; 86 75 87 76 // refer to variables.less 88 77 window._styles = {
+1 -1
resources/js/beatmap-discussions/beatmap-list.tsx
··· 41 41 42 42 componentDidMount() { 43 43 $(document).on(`click.${this.eventId}`, this.onDocumentClick); 44 - $(document).on(`turbolinks:before-cache.${this.eventId}`, this.handleBeforeCache); 44 + $(document).on(`turbo:before-cache.${this.eventId}`, this.handleBeforeCache); 45 45 } 46 46 47 47 componentWillUnmount() {
+6 -6
resources/js/beatmap-discussions/main.tsx
··· 13 13 import { parseUrl } from 'utils/beatmapset-discussion-helper'; 14 14 import { parseJson, storeJson } from 'utils/json'; 15 15 import { nextVal } from 'utils/seq'; 16 - import { currentUrl } from 'utils/turbolinks'; 16 + import { updateHistory, currentUrl } from 'utils/turbolinks'; 17 17 import { Discussions } from './discussions'; 18 18 import DiscussionsState from './discussions-state'; 19 19 import DiscussionsStateWorker from './discussions-state-worker'; ··· 59 59 componentDidMount() { 60 60 $(document).on(`ajax:success.${this.eventId}`, '.js-beatmapset-discussion-update', this.ujsDiscussionUpdate); 61 61 $(document).on(`click.${this.eventId}`, '.js-beatmap-discussion--jump', this.jumpToClick); 62 - document.addEventListener('turbolinks:before-cache', this.destroy); 62 + document.addEventListener('turbo:before-cache', this.destroy); 63 63 64 64 this.disposers.add(core.reactTurbolinks.runAfterPageLoad(action(() => { 65 65 this.jumpToDiscussionByHash(); 66 66 67 67 // normalize url after first render because the default discussion filter depends on ranked state. 68 - Turbolinks.controller.replaceHistory(this.discussionsState.url); 68 + updateHistory(this.discussionsState.url, 'replace'); 69 69 70 70 // Watch for reactions after the initial render and url normalization; 71 - // we don't want state changes to trigger advanceHistory on first render. 71 + // we don't want state changes to trigger updateHistory on first render. 72 72 this.disposers.add( 73 73 reaction(() => this.discussionsState.url, (current, prev) => { 74 74 if (current !== prev) { 75 - Turbolinks.controller.advanceHistory(current); 75 + updateHistory(current, 'push'); 76 76 } 77 77 }), 78 78 ); ··· 136 136 } 137 137 138 138 private readonly destroy = () => { 139 - document.removeEventListener('turbolinks:before-cache', this.destroy); 139 + document.removeEventListener('turbo:before-cache', this.destroy); 140 140 141 141 document.documentElement.style.removeProperty('--scroll-padding-top-extra'); 142 142
+1 -1
resources/js/beatmap-discussions/nominations.tsx
··· 154 154 route('beatmapsets.destroy', { beatmapset: this.beatmapset.id }), 155 155 { method: 'DELETE' }, 156 156 ) 157 - .done(() => Turbolinks.visit(route('users.show', { user: this.beatmapset.user_id }))) 157 + .done(() => Turbo.visit(route('users.show', { user: this.beatmapset.user_id }))) 158 158 .fail(onError) 159 159 .always(action(() => { 160 160 this.xhr.delete = undefined;
+3 -3
resources/js/beatmaps/beatmapset-search-controller.ts
··· 10 10 import core from 'osu-core-singleton'; 11 11 import { trans, transArray } from 'utils/lang'; 12 12 import { popup } from 'utils/popup'; 13 - import { currentUrl } from 'utils/turbolinks'; 13 + import { updateHistory, currentUrl } from 'utils/turbolinks'; 14 14 import { updateQueryString } from 'utils/url'; 15 15 16 16 ··· 165 165 166 166 private filterChangedSearch() { 167 167 const url = route('beatmapsets.index', this.filters.queryParams); 168 - Turbolinks.controller.advanceHistory(url); 168 + updateHistory(url, 'push'); 169 169 170 170 this.search(); 171 171 } ··· 180 180 this.filters = new BeatmapsetSearchFilters(url); 181 181 182 182 // normalize url 183 - Turbolinks.controller.replaceHistory(updateQueryString(null, { ...this.filters.queryParams })); 183 + updateHistory(updateQueryString(null, { ...this.filters.queryParams }), 'replace'); 184 184 185 185 this.filtersObserver = observe(this.filters, this.filterChangedHandler); 186 186
+1 -1
resources/js/beatmaps/main.tsx
··· 35 35 36 36 componentDidMount() { 37 37 disposeOnUnmount(this, reaction(() => controller.searchStatus, this.scrollPositionHandler)); 38 - $(document).on(`turbolinks:before-visit.${this.eventId}`, () => { 38 + $(document).on(`turbo:before-visit.${this.eventId}`, () => { 39 39 controller.cancel(); 40 40 }); 41 41 }
-1
resources/js/beatmapset-panel/index.tsx
··· 564 564 ) : ( 565 565 <a 566 566 className='beatmapset-panel__menu-item' 567 - data-turbolinks='false' 568 567 href={this.downloadLink.url} 569 568 title={this.downloadLink.title} 570 569 >
+2 -2
resources/js/beatmapsets-show/controller.ts
··· 99 99 100 100 makeObservable(this); 101 101 102 - $(document).on('turbolinks:before-cache', this.saveState); 102 + $(document).on('turbo:before-cache', this.saveState); 103 103 } 104 104 105 105 destroy() { 106 106 this.saveState(); 107 - $(document).off('turbolinks:before-cache', this.saveState); 107 + $(document).off('turbo:before-cache', this.saveState); 108 108 } 109 109 110 110 mapper(beatmap: BeatmapJsonForBeatmapsetShow) {
-3
resources/js/beatmapsets-show/header.tsx
··· 216 216 href={href} 217 217 icon={icon} 218 218 modifiers='beatmapset-header' 219 - props={{ 220 - 'data-turbolinks': 'false', 221 - }} 222 219 text={{ 223 220 bottom: bottomTextKey == null ? undefined : trans(`beatmapsets.show.details.download.${bottomTextKey}`), 224 221 top: trans(`beatmapsets.show.details.download.${topTextKey}`),
+1 -1
resources/js/beatmapsets-show/main.tsx
··· 64 64 65 65 componentDidMount() { 66 66 this.setHashDisposer = autorun(this.setHash); 67 - $(document).one('turbolinks:before-cache', () => this.setHashDisposer?.()); 67 + $(document).one('turbo:before-cache', () => this.setHashDisposer?.()); 68 68 } 69 69 70 70 componentWillUnmount() {
+2 -2
resources/js/beatmapsets-show/scoreboard/controller.ts
··· 88 88 89 89 makeObservable(this); 90 90 91 - $(document).on('turbolinks:before-cache', this.storeState); 91 + $(document).on('turbo:before-cache', this.storeState); 92 92 93 93 // fetch score data if needed 94 94 this.setCurrent({}); ··· 103 103 this.xhr?.abort(); 104 104 this.disposers.forEach((d) => d?.()); 105 105 this.storeState(); 106 - $(document).off('turbolinks:before-cache', this.storeState); 106 + $(document).off('turbo:before-cache', this.storeState); 107 107 } 108 108 109 109 @action
+7 -6
resources/js/chat/chat-state-store.ts
··· 17 17 import ChannelStore from 'stores/channel-store'; 18 18 import { isJqXHR, onError } from 'utils/ajax'; 19 19 import { hideLoadingOverlay } from 'utils/loading-overlay'; 20 + import { updateHistory } from 'utils/turbolinks'; 20 21 import { updateQueryString } from 'utils/url'; 21 22 import ChannelId, { AddChannelType } from './channel-id'; 22 23 import ChannelJoinEvent from './channel-join-event'; ··· 83 84 84 85 makeObservable(this); 85 86 86 - document.addEventListener('turbolinks:before-cache', this.handleBeforeCache); 87 + document.addEventListener('turbo:before-cache', this.handleBeforeCache); 87 88 88 89 observe(channelStore.channels, (changes) => { 89 90 // refocus channels if any gets removed ··· 173 174 } 174 175 175 176 @action 176 - selectChannel(channelId: ChannelId, mode: 'advanceHistory' | 'replaceHistory' | null = 'advanceHistory') { 177 + selectChannel(channelId: ChannelId, mode: 'push' | 'replace' | null = 'push') { 177 178 this.waitAddChannelId = null; // reset any waiting for channel. 178 179 // Mark the channel being switched away from as read. 179 180 // Marking as read is done here to avoid constantly sending mark-as-read requests ··· 204 205 205 206 this.selectChannel(this.channelList[0].channelId, null); 206 207 // Remove channel_id from location on selectFirst(); 207 - Turbolinks.controller.replaceHistory(updateQueryString(null, { 208 + updateHistory(updateQueryString(null, { 208 209 channel_id: null, 209 210 sendto: null, 210 - })); 211 + }), 'replace'); 211 212 } 212 213 213 214 @action ··· 307 308 }); 308 309 } 309 310 310 - private updateUrl(channel: Channel | AddChannelType, mode: 'advanceHistory' | 'replaceHistory' | null) { 311 + private updateUrl(channel: Channel | AddChannelType, mode: 'push' | 'replace' | null) { 311 312 if (mode == null) return; 312 313 313 314 let hash = ''; ··· 323 324 } 324 325 } 325 326 326 - Turbolinks.controller[mode](updateQueryString(null, params, hash)); 327 + updateHistory(updateQueryString(null, params, hash), mode); 327 328 } 328 329 }
+2 -2
resources/js/chat/conversation-panel.tsx
··· 22 22 constructor(props: Record<string, never>) { 23 23 super(props); 24 24 25 - document.addEventListener('turbolinks:before-cache', this.handleBeforeCache); 25 + document.addEventListener('turbo:before-cache', this.handleBeforeCache); 26 26 27 27 this.disposer = autorun(() => { 28 28 // Don't set title if this is on the document that is going away. ··· 40 40 41 41 componentWillUnmount() { 42 42 this.disposer(); 43 - document.removeEventListener('turbolinks:before-cache', this.handleBeforeCache); 43 + document.removeEventListener('turbo:before-cache', this.handleBeforeCache); 44 44 45 45 if (!core.dataStore.chatState.isChatMounted) { 46 46 core.browserTitleWithNotificationCount.title = null;
+2 -2
resources/js/components/comments-controller.ts
··· 156 156 157 157 makeObservable(this); 158 158 159 - document.addEventListener('turbolinks:before-cache', this.destroy); 159 + document.addEventListener('turbo:before-cache', this.destroy); 160 160 } 161 161 162 162 @action ··· 390 390 readonly destroy = () => { 391 391 if (this.destroyed) return; 392 392 393 - document.removeEventListener('turbolinks:before-cache', this.destroy); 393 + document.removeEventListener('turbo:before-cache', this.destroy); 394 394 abortXhrCollection(this.xhr); 395 395 this.stateStore(); 396 396 this.destroyed = true;
+2 -2
resources/js/components/modal.tsx
··· 20 20 21 21 componentDidMount() { 22 22 document.addEventListener('keydown', this.handleEsc); 23 - $(document).on('turbolinks:before-cache', this.handleBeforeCache); 23 + $(document).on('turbo:before-cache', this.handleBeforeCache); 24 24 25 25 this.open(); 26 26 } ··· 28 28 componentWillUnmount() { 29 29 this.close(); 30 30 document.removeEventListener('keydown', this.handleEsc); 31 - $(document).off('turbolinks:before-cache', this.handleBeforeCache); 31 + $(document).off('turbo:before-cache', this.handleBeforeCache); 32 32 } 33 33 34 34 render() {
-1
resources/js/components/play-detail-menu.tsx
··· 43 43 {hasReplay(score) && ( 44 44 <a 45 45 className='simple-menu__item js-login-required--click' 46 - data-turbolinks={false} 47 46 href={scoreDownloadUrl(score)} 48 47 onClick={dismiss} 49 48 >
+2 -2
resources/js/components/report-form.tsx
··· 123 123 } 124 124 125 125 componentDidMount() { 126 - $(document).on('turbolinks:before-cache', this.handleClose); 126 + $(document).on('turbo:before-cache', this.handleClose); 127 127 } 128 128 129 129 componentWillUnmount() { 130 - $(document).off('turbolinks:before-cache', this.handleClose); 130 + $(document).off('turbo:before-cache', this.handleClose); 131 131 window.clearTimeout(this.timeout); 132 132 } 133 133
+1 -1
resources/js/components/user-card-tooltip.tsx
··· 205 205 $(document).on('mouseover', '.js-usercard', onMouseOver); 206 206 $(document).on('mouseenter', '.js-react--user-card-tooltip', onMouseEnter); 207 207 $(document).on('mouseleave', '.js-react--user-card-tooltip', onMouseLeave); 208 - $(document).on('turbolinks:before-cache', onBeforeCache); 208 + $(document).on('turbo:before-cache', onBeforeCache); 209 209 $.subscribe('user-card:remove.tooltip', onRemoveUserCard); 210 210 } 211 211
+5 -5
resources/js/components/user-list.tsx
··· 10 10 import * as React from 'react'; 11 11 import { classWithModifiers } from 'utils/css'; 12 12 import { trans } from 'utils/lang'; 13 - import { currentUrlParams } from 'utils/turbolinks'; 13 + import { currentUrlParams, updateHistory } from 'utils/turbolinks'; 14 14 import { updateQueryString } from 'utils/url'; 15 15 import { Sort } from './sort'; 16 16 import { ViewMode, viewModes } from './user-card'; ··· 109 109 const value = (event.currentTarget as HTMLElement).dataset.value; 110 110 const url = updateQueryString(null, { sort: value }); 111 111 112 - Turbolinks.controller.advanceHistory(url); 112 + updateHistory(url, 'push'); 113 113 this.setState({ sortMode: value }, () => { 114 114 core.userPreferences.set('user_list_sort', this.state.sortMode); 115 115 }); ··· 119 119 const value = (event.currentTarget as HTMLElement).dataset.value; 120 120 const url = updateQueryString(null, { view: value }); 121 121 122 - Turbolinks.controller.advanceHistory(url); 122 + updateHistory(url, 'push'); 123 123 this.setState({ viewMode: value }, () => { 124 124 core.userPreferences.set('user_list_view', this.state.viewMode); 125 125 }); ··· 130 130 const key = (event.currentTarget as HTMLElement).dataset.key; 131 131 const url = updateQueryString(null, { filter: key }); 132 132 133 - Turbolinks.controller.advanceHistory(url); 133 + updateHistory(url, 'push'); 134 134 this.setState({ filter: key }, () => { 135 135 core.userPreferences.set('user_list_filter', this.state.filter); 136 136 }); ··· 140 140 const value = (event.currentTarget as HTMLElement).dataset.value; 141 141 const url = updateQueryString(null, { mode: value }); 142 142 143 - Turbolinks.controller.advanceHistory(url); 143 + updateHistory(url, 'push'); 144 144 this.setState({ playMode: value }); 145 145 }; 146 146
+1 -1
resources/js/core-legacy/changelog-chart-loader.coffee
··· 8 8 9 9 constructor: -> 10 10 $(window).on 'resize', @resize 11 - $(document).on 'turbolinks:load', @initialize 11 + $(document).on 'turbo:load', @initialize 12 12 13 13 initialize: => 14 14 return if !@container[0]?
+1 -1
resources/js/core-legacy/fancy-graph.coffee
··· 9 9 10 10 constructor: -> 11 11 $(window).on 'resize', @resize 12 - $(document).on 'turbolinks:load', @initialize 12 + $(document).on 'turbo:load', @initialize 13 13 14 14 15 15 initialize: =>
+1 -1
resources/js/core-legacy/form-toggle.coffee
··· 3 3 4 4 export default class FormToggle 5 5 constructor: -> 6 - addEventListener 'turbolinks:load', @sync 6 + addEventListener 'turbo:load', @sync 7 7 $(document).on 'change', '.js-form-toggle--input', @onChange 8 8 9 9
+1 -1
resources/js/core-legacy/forum-auto-click.coffee
··· 6 6 @_triggerDistance = 1200 7 7 @throttledOnScroll = _.throttle @onScroll, 1000 8 8 9 - $(document).on 'turbolinks:load', @onLoad 9 + $(document).on 'turbo:load', @onLoad 10 10 11 11 12 12 commonClick: (link) ->
+1 -1
resources/js/core-legacy/forum-cover.coffee
··· 21 21 $(document).on 'dragenter', '.js-forum-cover--overlay', => @setOverlay('hover') 22 22 $(document).on 'dragleave', '.js-forum-cover--overlay', => @setOverlay('active') 23 23 24 - $(document).on 'turbolinks:load', @refresh 24 + $(document).on 'turbo:load', @refresh 25 25 26 26 27 27 $uploadButton: => $(@uploadButton[0])
+1 -1
resources/js/core-legacy/forum-posts-seek.coffee
··· 15 15 16 16 $(document).on 'click', '.js-forum-posts-seek--jump', @jump 17 17 18 - addEventListener 'turbolinks:before-cache', @reset 18 + addEventListener 'turbo:before-cache', @reset 19 19 20 20 21 21 hideTooltip: =>
+1 -1
resources/js/core-legacy/forum-topic-reply.coffee
··· 22 22 23 23 $.subscribe 'stickyFooter', @stickOrUnstick 24 24 25 - $(document).on 'turbolinks:load', @initialize 25 + $(document).on 'turbo:load', @initialize 26 26 27 27 28 28 marker: -> document.querySelector('.js-sticky-footer[data-sticky-footer-target="forum-topic-reply"]')
+1 -1
resources/js/core-legacy/forum-topic-title.coffee
··· 12 12 @title = document.getElementsByClassName('js-forum-topic-title--title') 13 13 @toggleables = document.getElementsByClassName('js-forum-topic-title--toggleable') 14 14 15 - addEventListener 'turbolinks:before-cache', @abort 15 + addEventListener 'turbo:before-cache', @abort 16 16 $(document).on 'click', '.js-forum-topic-title--edit-start', @editShow 17 17 $(document).on 'click', '.js-forum-topic-title--save', @save 18 18 $(document).on 'keyup', '.js-forum-topic-title--input', @onKeyup
+7 -7
resources/js/core-legacy/forum.coffee
··· 7 7 import { bottomPage, formatNumber, isInputElement } from 'utils/html' 8 8 import { hideLoadingOverlay } from 'utils/loading-overlay' 9 9 import { present } from 'utils/string' 10 - import { currentUrl } from 'utils/turbolinks' 10 + import { currentUrl, updateHistory } from 'utils/turbolinks' 11 11 12 12 replaceUrl = (url) -> 13 - Turbolinks.controller.replaceHistory url 13 + updateHistory url, 'replace' 14 14 15 15 # browsers have limit on replaceState calls 16 16 debouncedReplaceUrl = _.debounce replaceUrl, 250 ··· 35 35 36 36 @maxPosts = 250 37 37 38 - $(document).on 'turbolinks:load', @throttledBoot 38 + $(document).on 'turbo:load', @throttledBoot 39 39 40 40 $(window).on 'scroll', @refreshCounter 41 41 $(document).on 'click', '.js-forum-posts-show-more', @showMore ··· 43 43 $(document).on 'submit', '.js-forum-posts-jump-to', @jumpToSubmit 44 44 $(document).on 'keyup', @keyboardNavigation 45 45 $(document).on 'click', '.js-forum-topic-moderate--toggle-deleted', @toggleDeleted 46 - $(document).on 'turbolinks:before-cache', debouncedReplaceUrl.cancel 46 + $(document).on 'turbo:before-cache', debouncedReplaceUrl.cancel 47 47 48 48 49 49 userCanModerate: -> ··· 196 196 if $post.length 197 197 @scrollTo $post.attr('data-post-id') 198 198 else 199 - Turbolinks.visit @postUrlN(postN) 199 + Turbo.visit @postUrlN(postN) 200 200 201 201 true 202 202 ··· 246 246 toggleDeleted: => 247 247 xhr = osuCore.userPreferences.set('forum_posts_show_deleted', !@showDeleted()) 248 248 249 - callback = => Turbolinks.visit @postUrlN(@currentPostPosition) 249 + callback = => Turbo.visit @postUrlN(@currentPostPosition) 250 250 251 251 if xhr? 252 252 xhr.done callback ··· 260 260 return if !topicMeta? 261 261 262 262 history.scrollRestoration = 'manual' 263 - $(document).one 'turbolinks:before-cache', -> 263 + $(document).one 'turbo:before-cache', -> 264 264 history.scrollRestoration = 'auto' 265 265 266 266 shouldScroll = currentUrl().hash == '' && present(topicMeta.postJumpTo)
+1 -1
resources/js/core-legacy/gallery.coffee
··· 13 13 $(document).on 'click', '.js-gallery', @initiateOpen 14 14 $(document).on 'click', '.js-gallery-thumbnail', @switchPreview 15 15 16 - $(document).on 'turbolinks:before-cache', -> 16 + $(document).on 'turbo:before-cache', -> 17 17 $('.js-gallery--container').remove() 18 18 19 19
+1 -1
resources/js/core-legacy/landing-graph.coffee
··· 9 9 10 10 constructor: -> 11 11 $(window).on 'resize', @resize 12 - $(document).on 'turbolinks:load', @initialize 12 + $(document).on 'turbo:load', @initialize 13 13 14 14 15 15 initialize: =>
+1 -1
resources/js/core-legacy/menu.coffee
··· 11 11 $(document).on 'mouseenter', '.js-menu', @onMouseEnter 12 12 $(document).on 'mouseleave', '.js-menu', @onMouseLeave 13 13 $(document).on 'touchstart', @onGlobalTouchstart 14 - $(document).on 'turbolinks:load', @onDocumentReady 14 + $(document).on 'turbo:load', @onDocumentReady 15 15 16 16 17 17 $menuLink: (id) -> $(".js-menu[data-menu-target#{if id then "='#{id}'" else ''}]")
+1 -1
resources/js/core-legacy/nav-button.coffee
··· 7 7 @items = document.getElementsByClassName 'js-nav-button--item' 8 8 @main = document.getElementsByClassName 'js-nav-button' 9 9 10 - addEventListener 'turbolinks:load', @load 10 + addEventListener 'turbo:load', @load 11 11 12 12 13 13 load: =>
+3 -3
resources/js/core-legacy/search.coffee
··· 9 9 $(document).on 'input', '.js-search--input', @debouncedSubmitInput 10 10 $(document).on 'keydown', '.js-search--input', @maybeSubmitInput 11 11 $(document).on 'submit', '.js-search', @submitForm 12 - addEventListener 'turbolinks:load', @restoreFocus 12 + addEventListener 'turbo:load', @restoreFocus 13 13 14 14 15 15 forumPostReset: => ··· 46 46 @searchingToggle(true) 47 47 params = $('.js-search').serialize() 48 48 49 - $(document).one 'turbolinks:before-cache', => 49 + $(document).one 'turbo:before-cache', => 50 50 @activeElement = document.activeElement 51 51 @searchingToggle(false) 52 52 53 - Turbolinks.visit("?#{params}") 53 + Turbo.visit("?#{params}") 54 54 55 55 56 56 searchingToggle: (state) =>
+1 -1
resources/js/core-legacy/tooltip-default.coffee
··· 7 7 constructor: -> 8 8 $(document).on 'mouseover touchstart', '[title]:not(iframe)', @onMouseOver 9 9 $(document).on 'mouseenter touchstart', '.u-ellipsis-overflow, .u-ellipsis-overflow-desktop, .u-ellipsis-pre-overflow', @autoAddTooltip 10 - $(document).on 'turbolinks:load', @rollback 10 + $(document).on 'turbo:load', @rollback 11 11 12 12 13 13 onMouseOver: (event) =>
+2 -2
resources/js/core/account-edit-avatar.ts
··· 16 16 private overlayLeaveTimeout?: number; 17 17 18 18 constructor(private readonly core: OsuCore) { 19 - $(document).on('turbolinks:load', this.initialize); 20 - $(document).on('turbolinks:before-cache', this.rollback); 19 + $(document).on('turbo:load', this.initialize); 20 + $(document).on('turbo:before-cache', this.rollback); 21 21 22 22 $.subscribe('dragenterGlobal', this.overlayStart); 23 23 $.subscribe('dragendGlobal', this.overlayEnd);
+2 -2
resources/js/core/animate-nav.ts
··· 4 4 export default class AnimateNav { 5 5 constructor() { 6 6 $(document) 7 - .on('turbolinks:before-cache', () => { 7 + .on('turbo:before-cache', () => { 8 8 document.body.classList.remove('js-animate-nav'); 9 - }).on('turbolinks:load', () => { 9 + }).on('turbo:load', () => { 10 10 window.setTimeout(() => { 11 11 document.body.classList.add('js-animate-nav'); 12 12 }, 0);
+2 -2
resources/js/core/browser-title-with-notification-count.ts
··· 18 18 19 19 constructor(private readonly core: OsuCore) { 20 20 makeObservable(this); 21 - document.addEventListener('turbolinks:load', this.setTitle); 22 - document.addEventListener('turbolinks:before-cache', this.resetTitle); 21 + document.addEventListener('turbo:load', this.setTitle); 22 + document.addEventListener('turbo:before-cache', this.resetTitle); 23 23 } 24 24 25 25 @action
+2 -2
resources/js/core/captcha.ts
··· 18 18 private sitekey = ''; 19 19 20 20 constructor() { 21 - $(document).on('turbolinks:load', this.renderAll); 21 + $(document).on('turbo:load', this.renderAll); 22 22 $(document).on('ajax:error', '.js-captcha--reset-on-error', this.resetOnError); 23 23 } 24 24 ··· 74 74 throw new Error('failed setting up turnstile widget'); 75 75 } 76 76 container.dataset.captchaId = id; 77 - $(document).one('turbolinks:before-cache', () => this.remove(container)); 77 + $(document).one('turbo:before-cache', () => this.remove(container)); 78 78 79 79 disableSubmit(); 80 80 }
+2 -2
resources/js/core/click-menu.ts
··· 13 13 $(document).on('click', '.js-click-menu[data-click-menu-target]', this.toggle); 14 14 $(document).on('mousedown', this.onDocumentMousedown); 15 15 $(document).on('mouseup', this.onDocumentMouseup); 16 - document.addEventListener('turbolinks:load', this.restoreSaved); 17 - document.addEventListener('turbolinks:before-cache', this.saveCurrent); 16 + document.addEventListener('turbo:load', this.restoreSaved); 17 + document.addEventListener('turbo:before-cache', this.saveCurrent); 18 18 } 19 19 20 20 close = () => {
+1 -1
resources/js/core/current-user-observer.ts
··· 10 10 private readonly covers = document.getElementsByClassName('js-current-user-cover'); 11 11 12 12 constructor(private readonly core: OsuCore) { 13 - $(document).on('turbolinks:load', this.setAvatars); 13 + $(document).on('turbo:load', this.setAvatars); 14 14 15 15 // one time setup to monitor user url variables. No disposer because nothing destroys this object. 16 16 $(() => reaction(() => this.core.currentUser?.avatar_url, this.setAvatars));
+2 -2
resources/js/core/enchant.ts
··· 13 13 14 14 export default class Enchant { 15 15 constructor(private readonly turbolinksReload: TurbolinksReload) { 16 - $(document).on('turbolinks:load', this.load); 17 - $(document).on('turbolinks:before-cache', this.unload); 16 + $(document).on('turbo:load', this.load); 17 + $(document).on('turbo:before-cache', this.unload); 18 18 $(document).on('click', '.js-enchant--show', this.showMessageWindow); 19 19 } 20 20
+1 -1
resources/js/core/forum/forum-post-input.ts
··· 21 21 constructor() { 22 22 $(document) 23 23 .on('input change', '.js-forum-post-input', this.onInput) 24 - .on('turbolinks:load', this.handlePageLoad) 24 + .on('turbo:load', this.handlePageLoad) 25 25 .on('ajax:success', '.js-forum-post-input--form', this.handlePostSaved); 26 26 $.subscribe('forum-post-input:restore', this.handleRestore); 27 27 $.subscribe('forum-post-input:clear', this.handleClear);
+1 -1
resources/js/core/osu-audio/main.ts
··· 119 119 .on('click', '.js-audio--toggle-mute', this.toggleMute) 120 120 .on('click', '.js-audio--toggle-autoplay', this.toggleAutoplay) 121 121 .on('click', '.js-audio--nav', this.nav); 122 - document.addEventListener('turbolinks:load', this.onDocumentReady); 122 + document.addEventListener('turbo:load', this.onDocumentReady); 123 123 } 124 124 125 125 private readonly checkVolumeSettings = () => {
+2 -2
resources/js/core/osu-audio/slider.ts
··· 35 35 $(document).on('mousemove touchmove', this.onMove); 36 36 $(document).on('mouseup touchend', this.end); 37 37 $(window).on('blur', this.end); 38 - $(document).on('turbolinks:before-cache', this.end); 38 + $(document).on('turbo:before-cache', this.end); 39 39 } 40 40 41 41 static start(params: Params) { ··· 58 58 $(document).off('mousemove touchmove', this.onMove); 59 59 $(document).off('mouseup touchend', this.end); 60 60 $(window).off('blur', this.end); 61 - $(document).off('turbolinks:before-cache', this.end); 61 + $(document).off('turbo:before-cache', this.end); 62 62 63 63 if (this.endCallback != null) { 64 64 this.endCallback(this);
+35 -28
resources/js/core/react-turbolinks.ts
··· 1 1 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 + import { TurboBeforeRenderEvent } from '@hotwired/turbo'; 4 5 import { removeLeftoverPortalContainers } from 'components/portal'; 5 6 import TurbolinksReload from 'core/turbolinks-reload'; 6 7 import { runInAction } from 'mobx'; ··· 20 21 private timeoutScroll?: number; 21 22 22 23 constructor(private readonly core: OsuCore, private readonly turbolinksReload: TurbolinksReload) { 23 - $(document).on('turbolinks:before-cache', this.handleBeforeCache); 24 - $(document).on('turbolinks:before-visit', this.handleBeforeVisit); 25 - $(document).on('turbolinks:load', this.handleLoad); 26 - $(document).on('turbolinks:before-render', this.handleBeforeRender); 24 + $(document).on('turbo:before-cache', this.handleBeforeCache); 25 + $(document).on('turbo:before-visit', this.handleBeforeVisit); 26 + $(document).on('turbo:load', this.handleLoad); 27 + document.addEventListener('turbo:before-render', this.handleBeforeRender); 27 28 } 28 29 29 30 boot = () => { ··· 58 59 if (document.body === window.newBody) { 59 60 callback(); 60 61 } else { 61 - $(document).one('turbolinks:load', callback); 62 + $(document).one('turbo:load', callback); 62 63 63 64 return () => { 64 - $(document).off('turbolinks:load', callback); 65 + $(document).off('turbo:load', callback); 65 66 }; 66 67 } 67 68 } ··· 80 81 window.clearTimeout(this.timeoutScroll); 81 82 }; 82 83 83 - private readonly handleBeforeRender = (e: JQuery.TriggeredEvent) => { 84 - window.newBody = (e.originalEvent as Event & { data: { newBody: HTMLElement } }).data.newBody; 84 + private readonly handleBeforeRender = (e: TurboBeforeRenderEvent) => { 85 + e.preventDefault(); 86 + 87 + window.newBody = e.detail.newBody; 85 88 this.setNewUrl(); 86 89 this.pageReady = true; 87 90 removeLeftoverPortalContainers(); 88 91 this.core.updateCurrentUser(); 89 - this.loadScripts(false); 90 - this.boot(); 92 + this.loadScripts().then(() => { 93 + this.boot(); 94 + e.detail.resume(); 95 + }); 91 96 }; 92 97 93 98 private readonly handleBeforeVisit = () => { ··· 105 110 // Delayed to wait until cacheSnapshot finishes. The delay matches Turbolinks' defer. 106 111 window.setTimeout(() => { 107 112 this.destroy(); 108 - this.loadScripts(); 109 - this.boot(); 110 - this.timeoutScroll = window.setTimeout(this.scrollOnNewVisit, 100); 113 + this.loadScripts().then(() => { 114 + this.boot(); 115 + this.timeoutScroll = window.setTimeout(this.scrollOnNewVisit, 100); 116 + }); 111 117 }, 1); 112 118 }; 113 119 ··· 115 121 this.scrolled = this.scrolled || window.scrollX !== 0 || window.scrollY !== 0; 116 122 }; 117 123 118 - private loadScripts(isAsync = true) { 119 - if (window.newBody == null) return; 124 + private loadScripts() { 125 + const promises: Promise<unknown>[] = []; 120 126 121 - const loadFunc = isAsync ? 'load' : 'loadSync'; 127 + if (window.newBody != null) { 128 + window.newBody.querySelectorAll('.js-react-turbolinks--script').forEach((script) => { 129 + if (script instanceof HTMLDivElement) { 130 + const src = script.dataset.src; 131 + if (src != null) { 132 + promises.push(this.turbolinksReload.load(src)); 133 + } 134 + } 135 + }); 136 + } 122 137 123 - window.newBody.querySelectorAll('.js-react-turbolinks--script').forEach((script) => { 124 - if (script instanceof HTMLDivElement) { 125 - const src = script.dataset.src; 126 - if (src != null) { 127 - void this.turbolinksReload[loadFunc](src); 128 - } 129 - } 130 - }); 138 + return Promise.all(promises); 131 139 } 132 140 133 141 private readonly scrollOnNewVisit = () => { ··· 145 153 }; 146 154 147 155 private setNewUrl() { 148 - const visitUrl = Turbolinks.controller.currentVisit?.redirectedToLocation?.absoluteURL 149 - ?? Turbolinks.controller.currentVisit?.location.absoluteURL; 150 - 151 - window.newUrl = visitUrl == null ? document.location : new URL(visitUrl); 156 + window.newUrl = Turbo.session.navigator.currentVisit?.redirectedToLocation 157 + ?? Turbo.session.navigator.currentVisit?.location 158 + ?? document.location; 152 159 } 153 160 }
+1 -1
resources/js/core/sticky-footer.ts
··· 20 20 21 21 $(window).on('scroll resize', this.stickOrUnstick); 22 22 $.subscribe('stickyFooter:check', this.throttledStickOrUnstick); 23 - $(document).on('turbolinks:load', this.throttledStickOrUnstick); 23 + $(document).on('turbo:load', this.throttledStickOrUnstick); 24 24 } 25 25 26 26 markerDisable(el: HTMLElement) {
+1 -1
resources/js/core/sticky-header.ts
··· 63 63 64 64 constructor() { 65 65 $(window).on('scroll', this.onScroll); 66 - $(document).on('turbolinks:load', this.onScroll); 66 + $(document).on('turbo:load', this.onScroll); 67 67 $(window).on('resize', this.stickOrUnstick); 68 68 } 69 69
+1 -1
resources/js/core/sync-height.ts
··· 7 7 private readonly targets = document.getElementsByClassName('js-sync-height--target'); 8 8 9 9 constructor() { 10 - $(document).on('turbolinks:load', this.sync); 10 + $(document).on('turbo:load', this.sync); 11 11 $.subscribe('sync-height:force', this.sync); 12 12 $(window).on('resize', this.sync); 13 13
+1 -1
resources/js/core/twitch-player.tsx
··· 18 18 private readonly playerDivs = document.getElementsByClassName('js-twitch-player'); 19 19 20 20 constructor(private readonly turbolinksReload: TurbolinksReload) { 21 - document.addEventListener('turbolinks:load', this.startAll); 21 + document.addEventListener('turbo:load', this.startAll); 22 22 } 23 23 24 24 initializeEmbed() {
+1 -1
resources/js/core/user/user-login.ts
··· 46 46 .on('click', '.js-login-required--click', this.showToContinue) 47 47 .on('ajax:before', '.js-login-required--click', () => core.currentUser != null) 48 48 .on('ajax:error', this.onError) 49 - .on('turbolinks:load', this.showOnLoad); 49 + .on('turbo:load', this.showOnLoad); 50 50 $.subscribe('nav:popup:hidden', this.reset); 51 51 } 52 52
+4 -4
resources/js/core/user/user-verification.ts
··· 39 39 export default class UserVerification { 40 40 // Used as callback on original action (where verification was required) 41 41 private callback?: () => void; 42 - // set to true on turbolinks:visit so the box will be rendered on navigation 42 + // set to true on turbo:visit so the box will be rendered on navigation 43 43 private delayShow = false; 44 44 // actual function to "store" the parameter original used for delayed show call 45 45 private delayShowCallback?: () => void; ··· 70 70 constructor() { 71 71 $(document) 72 72 .on('ajax:error', this.onError) 73 - .on('turbolinks:load', this.setModal) 74 - .on('turbolinks:load', this.showOnLoad) 75 - .on('turbolinks:visit', this.setDelayShow) 73 + .on('turbo:load', this.setModal) 74 + .on('turbo:load', this.showOnLoad) 75 + .on('turbo:visit', this.setDelayShow) 76 76 .on('input', '.js-user-verification--input', this.autoSubmit) 77 77 .on('click', '.js-user-verification--reissue', this.reissue); 78 78 $.subscribe('user-verification:success', this.success);
-1
resources/js/entrypoints/app.ts
··· 12 12 import 'ujs-common.coffee'; 13 13 import 'bootstrap-modal.coffee'; 14 14 import 'shared.coffee'; 15 - import 'turbolinks-overrides.coffee'; 16 15 17 16 import 'osu-core-singleton'; 18 17 import 'main.coffee';
+2 -2
resources/js/entrypoints/chat.tsx
··· 80 80 const channelId = currentUrl().hash.slice(1); 81 81 82 82 if (channelId === 'create' || channelId === 'join') { 83 - core.dataStore.chatState.selectChannel(channelId, 'replaceHistory'); 83 + core.dataStore.chatState.selectChannel(channelId, 'replace'); 84 84 } else { 85 85 const channel = getInitialChannel(initial?.send_to); 86 86 87 87 if (channel === undefined) { 88 88 core.dataStore.chatState.selectFirst(); 89 89 } else { 90 - core.dataStore.chatState.selectChannel(channel?.channelId ?? null, 'replaceHistory'); 90 + core.dataStore.chatState.selectChannel(channel?.channelId ?? null, 'replace'); 91 91 } 92 92 } 93 93
+1 -1
resources/js/forum/post-box.coffee
··· 48 48 insert e, openTag, closeTag 49 49 50 50 51 - $(document).on 'turbolinks:load', -> 51 + $(document).on 'turbo:load', -> 52 52 $('.js-bbcode-btn--size').val('') 53 53 54 54
+1 -1
resources/js/gallery-contest.tsx
··· 26 26 27 27 this.eventId = `gallery-contest-${nextVal()}`; 28 28 29 - $(document).on(`turbolinks:before-cache.${this.eventId}`, this.destroy); 29 + $(document).on(`turbo:before-cache.${this.eventId}`, this.destroy); 30 30 pswp.listen('destroy', this.destroy); 31 31 } 32 32
-1
resources/js/github-user/index.tsx
··· 57 57 <BigButton 58 58 href={route('account.github-users.create')} 59 59 icon='fas fa-link' 60 - props={{ 'data-turbolinks': 'false' }} 61 60 text={trans('accounts.github_user.link')} 62 61 /> 63 62 <div className='account-edit-entry__rules'>
-3
resources/js/globals.d.ts
··· 47 47 declare const process: Process; 48 48 // #endregion 49 49 50 - // TODO: Turbolinks 5.3 is Typescript, so this should be updated then...or it could be never released. 51 - declare const Turbolinks: import('turbolinks').default; 52 - 53 50 // our helpers 54 51 declare const tooltipDefault: import('legacy-modules').TooltipDefault; 55 52
+1 -13
resources/js/main.coffee
··· 28 28 import Search from 'core-legacy/search' 29 29 import { StoreCheckout } from 'core-legacy/store-checkout' 30 30 import TooltipDefault from 'core-legacy/tooltip-default' 31 - import { hideLoadingOverlay, showLoadingOverlay } from 'utils/loading-overlay' 32 31 import { navigate } from 'utils/turbolinks' 33 - 34 - Turbolinks.start() 35 - Turbolinks.setProgressBarDelay(0) 36 32 37 33 moment.relativeTimeThreshold('ss', 44) 38 34 moment.relativeTimeThreshold('s', 120) ··· 43 39 jQuery.timeago.inWords = (distanceMillis) -> 44 40 moment.duration(-1 * distanceMillis).humanize(true) 45 41 46 - # loading animation overlay 47 - # fired from turbolinks 48 - $(document).on 'turbolinks:request-start', showLoadingOverlay 49 - $(document).on 'turbolinks:request-end', hideLoadingOverlay 50 - # form submission is not covered by turbolinks 51 - $(document).on 'submit', 'form', (e) -> 52 - showLoadingOverlay() if e.currentTarget.dataset.loadingOverlay != '0' 53 - 54 - $(document).on 'turbolinks:load', -> 42 + $(document).on 'turbo:load', -> 55 43 BeatmapPack.initialize() 56 44 StoreCheckout.initialize() 57 45
+2 -1
resources/js/models/chat/create-announcement.ts
··· 4 4 import UserJson from 'interfaces/user-json'; 5 5 import { action, autorun, computed, makeObservable, observable } from 'mobx'; 6 6 import { present } from 'utils/string'; 7 + import { v4 as uuidv4 } from 'uuid'; 7 8 import { maxMessageLength } from './channel'; 8 9 9 10 interface LocalStorageProps extends Record<InputKey, string> { ··· 33 34 @observable validUsers = new Map<number, UserJson>(); 34 35 35 36 private initialized = false; 36 - private readonly uuid = crypto.randomUUID(); 37 + private readonly uuid = uuidv4(); 37 38 38 39 @computed 39 40 get errors() {
+2 -1
resources/js/models/chat/message.ts
··· 6 6 import User from 'models/user'; 7 7 import * as moment from 'moment'; 8 8 import core from 'osu-core-singleton'; 9 + import { v4 as uuidv4 } from 'uuid'; 9 10 10 11 export default class Message { 11 12 @observable channelId = -1; 12 13 @observable content = ''; 13 14 @observable errored = false; 14 15 @observable isAction = false; 15 - @observable messageId: number | string = crypto.randomUUID(); 16 + @observable messageId: number | string = uuidv4(); 16 17 @observable persisted = false; 17 18 @observable senderId = -1; 18 19 @observable timestamp: string = moment().toISOString();
+2 -2
resources/js/notifications/notification-controller.ts
··· 6 6 import { NotificationContextData } from 'notifications-context'; 7 7 import NotificationStackStore from 'stores/notification-stack-store'; 8 8 import NotificationStore from 'stores/notification-store'; 9 - import { currentUrl, currentUrlParams } from 'utils/turbolinks'; 9 + import { updateHistory, currentUrl, currentUrlParams } from 'utils/turbolinks'; 10 10 import { updateQueryString } from 'utils/url'; 11 11 12 12 export default class NotificationController { ··· 86 86 href = updateQueryString(null, { type }); 87 87 } 88 88 89 - Turbolinks.controller.advanceHistory(href); 89 + updateHistory(href, 'push'); 90 90 } 91 91 } 92 92
+2 -9
resources/js/osu-core.ts
··· 59 59 readonly currentUserObserver; 60 60 readonly dataStore; 61 61 readonly enchant; 62 + firstCurrentUserSet = false; 62 63 readonly forumPoll; 63 64 readonly forumPostEdit; 64 65 readonly forumPostInput; ··· 97 98 constructor() { 98 99 // Set current user on first page load. Further updates are done in 99 100 // reactTurbolinks before the new page is rendered. 100 - // This needs to be fired before everything else (turbolinks:load etc). 101 - const isLoading = document.readyState === 'loading'; 102 - if (isLoading) { 103 - document.addEventListener('DOMContentLoaded', this.updateCurrentUser); 104 - } 101 + // This needs to be fired before everything else (turbo:load etc). 105 102 $.subscribe('user:update', this.onCurrentUserUpdate); 106 103 107 104 this.animateNav = new AnimateNav(); ··· 150 147 this.notificationsWorker = new NotificationsWorker(this.socketWorker); 151 148 152 149 makeObservable(this); 153 - 154 - if (!isLoading) { 155 - this.updateCurrentUser(); 156 - } 157 150 } 158 151 159 152 @action
+2 -2
resources/js/profile-page/controller.tsx
··· 169 169 makeObservable(this); 170 170 171 171 $.subscribe('score:pin', this.onScorePinUpdate); 172 - $(document).on('turbolinks:before-cache', this.saveState); 172 + $(document).on('turbo:before-cache', this.saveState); 173 173 } 174 174 175 175 @action ··· 409 409 Object.values(this.xhr).forEach((xhr) => xhr?.abort()); 410 410 this.debouncedSetDisplayCoverUrl.cancel(); 411 411 $.unsubscribe('score:pin', this.onScorePinUpdate); 412 - $(document).off('turbolinks:before-cache', this.saveState); 412 + $(document).off('turbo:before-cache', this.saveState); 413 413 this.saveState(); 414 414 } 415 415
-1
resources/js/scores-show/buttons.tsx
··· 33 33 {hasReplay(props.score) && ( 34 34 <a 35 35 className='js-login-required--click btn-osu-big btn-osu-big--rounded' 36 - data-turbolinks={false} 37 36 href={scoreDownloadUrl(props.score)} 38 37 > 39 38 {trans('users.show.extra.top_ranks.download_replay')}
+15
resources/js/setup-jquery.ts
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + import jQuery from 'jquery'; 5 + import 'bootstrap'; 6 + import 'timeago/jquery.timeago.js'; 7 + import 'qtip2/dist/jquery.qtip.js'; 8 + import 'jquery.scrollto/jquery.scrollTo.js'; 9 + import 'jquery-ui/ui/data.js'; 10 + import 'jquery-ui/ui/widgets/slider.js'; 11 + import 'jquery-ui/ui/widgets/sortable.js'; 12 + import 'jquery-ui-touch-punch'; 13 + import 'blueimp-file-upload/js/jquery.fileupload.js'; 14 + 15 + window.$ = window.jQuery = jQuery;
+57
resources/js/setup-turbo.ts
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + import '@hotwired/turbo'; 5 + import { hideLoadingOverlay, showLoadingOverlay } from 'utils/loading-overlay'; 6 + import { reloadPage } from 'utils/turbolinks'; 7 + 8 + Turbo.config.drive.progressBarDelay = 0; 9 + 10 + // loading animation overlay 11 + document.addEventListener('turbo:visit', showLoadingOverlay); 12 + document.addEventListener('turbo:before-cache', hideLoadingOverlay); 13 + document.addEventListener('turbo:load', hideLoadingOverlay); 14 + // only for forms handled by turbo. jquery-ujs forms are handled separately 15 + document.addEventListener('turbo:submit-start', (e) => { 16 + if (e.detail.formSubmission.formElement.dataset.loadingOverlay !== '0') { 17 + showLoadingOverlay(); 18 + } 19 + }); 20 + document.addEventListener('turbo:submit-end', hideLoadingOverlay); 21 + document.addEventListener('turbo:submit-end', (e) => { 22 + if (e.detail.success && e.detail.formSubmission.formElement.dataset.reloadOnSuccess === '1') { 23 + reloadPage(); 24 + } 25 + }); 26 + 27 + document.addEventListener('turbo:before-fetch-response', (e) => { 28 + if (!e.detail.fetchResponse.contentType?.match(/^text\/osu-turbo-redirect[ ;]*/)) { 29 + return; 30 + } 31 + 32 + e.preventDefault(); 33 + e.detail.fetchResponse.responseText.then((url) => { 34 + const [currentUrlBase, urlBase] = [document.location.href, url].map((u) => u.replace(/#.*/, '')); 35 + 36 + if (currentUrlBase === urlBase) { 37 + // a normal/advance visit to same url won't reload the page 38 + Turbo.visit(url, { action: 'replace' }); 39 + } else { 40 + Turbo.visit(url); 41 + } 42 + }); 43 + }); 44 + 45 + // disable turbo navigation for old webs 46 + document.addEventListener('turbo:click', (event) => { 47 + const url = new URL(event.detail.url); 48 + 49 + if ( 50 + url.origin === Turbo.session.navigator.rootLocation.origin 51 + && url.pathname.match(/^\/(?:(?:api|osu|p|ss|web)\/|(?:beatmapsets|scores(?:\/[^\d]+)?)\/\d+\/download(?:\?|$))/) === null 52 + ) { 53 + return; 54 + } 55 + 56 + event.preventDefault(); 57 + });
+1 -1
resources/js/shared.coffee
··· 50 50 el.remove() 51 51 52 52 #populate last-submitted values 53 - $(document).on 'turbolinks:load', -> 53 + $(document).on 'turbo:load', -> 54 54 $('.content-editable-submit').each (_i, el) -> 55 55 $el = $(el) 56 56 $el.data('last-submitted-value', $el.html())
+1 -1
resources/js/store-username-change.coffee
··· 49 49 $status.text trans('store.username_change.checking', username: requestedUsername) 50 50 debouncedCheckUsernameValidity() 51 51 52 - $(document).on 'turbolinks:load', -> 52 + $(document).on 'turbo:load', -> 53 53 return if $('.js-username-change-input').length == 0 54 54 preventUsernameSubmission()
+1 -1
resources/js/store-xsolla.coffee
··· 15 15 16 16 17 17 @fetchScript: -> 18 - core.turbolinksReload.load('https://static.xsolla.com/embed/paystation/1.0.7/widget.min.js') ? Promise.resolve() 18 + core.turbolinksReload.load('https://static.xsolla.com/embed/paystation/1.0.7/widget.min.js') 19 19 20 20 21 21 @fetchToken: (orderNumber) ->
+3 -3
resources/js/store.ts
··· 23 23 $(document).on('click', '.js-store-checkout', (event: ClickEvent) => void this.beginCheckout(event)); 24 24 $(document).on('click', '.js-store-resume-checkout', (event: ClickEvent) => this.resumeCheckout(event)); 25 25 26 - $(document).on('turbolinks:load', () => { 26 + $(document).on('turbo:load', () => { 27 27 $('.js-store-checkout').prop('disabled', false); 28 28 }); 29 29 ··· 55 55 return; 56 56 } 57 57 58 - Turbolinks.visit(route('store.checkout.show', { checkout: orderId })); 58 + Turbo.visit(route('store.checkout.show', { checkout: orderId })); 59 59 } 60 60 61 61 async beginShopifyCheckout(orderId: string) { ··· 99 99 // TODO: show error. 100 100 } 101 101 } else { 102 - Turbolinks.visit(route('store.invoice.show', { invoice: target.dataset.orderId })); 102 + Turbo.visit(route('store.invoice.show', { invoice: target.dataset.orderId })); 103 103 } 104 104 } 105 105
+2 -2
resources/js/store/store-supporter-tag.tsx
··· 122 122 super(props); 123 123 124 124 this.debouncedGetUser = debounce(this.getUser, 300); 125 - document.addEventListener('turbolinks:before-cache', this.handleBeforeCache); 125 + document.addEventListener('turbo:before-cache', this.handleBeforeCache); 126 126 127 127 makeObservable(this); 128 128 ··· 156 156 } 157 157 158 158 componentWillUnmount() { 159 - document.removeEventListener('turbolinks:before-cache', this.handleBeforeCache); 159 + document.removeEventListener('turbo:before-cache', this.handleBeforeCache); 160 160 this.xhr?.abort(); 161 161 } 162 162
+52
resources/js/turbo-extended.d.ts
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + import '@hotwired/turbo'; 5 + 6 + declare module '@hotwired/turbo' { 7 + type LocationOrURL = Location | URL; 8 + 9 + interface FormSubmission { 10 + formElement: HTMLFormElement; 11 + } 12 + 13 + interface PageSnapshot { 14 + clone(): PageSnapshot; 15 + } 16 + 17 + interface SnapshotCache { 18 + put(location: LocationOrURL, snapshot: PageSnapshot): void; 19 + } 20 + 21 + interface TurboGlobal { 22 + cache: { 23 + clear(): void; 24 + }; 25 + config: { 26 + drive: { 27 + progressBarDelay: number; 28 + }; 29 + }; 30 + } 31 + 32 + interface TurboHistory { 33 + push(location: LocationOrURL, uuid: string): void; 34 + replace(location: LocationOrURL, uuid: string): void; 35 + } 36 + 37 + interface TurboSession { 38 + history: TurboHistory; 39 + navigator: { 40 + currentVisit?: { 41 + location: LocationOrURL; 42 + redirectedToLocation?: LocationOrURL; 43 + }; 44 + rootLocation: LocationOrURL; 45 + }; 46 + view: { 47 + lastRenderedLocation: LocationOrURL; 48 + snapshot: PageSnapshot; 49 + snapshotCache: SnapshotCache; 50 + }; 51 + } 52 + }
-36
resources/js/turbolinks.d.ts
··· 1 - // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 2 - // See the LICENCE file in the repository root for full licence text. 3 - 4 - declare module 'turbolinks' { 5 - interface Controller { 6 - advanceHistory(url: string): void; 7 - currentVisit?: Visit; 8 - replaceHistory(url: string): void; 9 - } 10 - 11 - interface Location { 12 - absoluteURL: string; 13 - } 14 - 15 - interface TurbolinksAction { 16 - action: 'advance' | 'replace' | 'restore'; 17 - } 18 - 19 - interface TurbolinksLocation { 20 - getPath(): string; 21 - isHTML(): boolean; 22 - } 23 - 24 - interface Visit { 25 - location: Location; 26 - redirectedToLocation?: Location; 27 - } 28 - 29 - export default interface TurbolinksStatic { 30 - clearCache(): void; 31 - controller: Controller; 32 - setProgressBarDelay(delayInMilliseconds: number): void; 33 - supported: boolean; 34 - visit(location: string, options?: TurbolinksAction): void; 35 - } 36 - }
+1 -1
resources/js/ujs-common.coffee
··· 19 19 if event.target.getAttribute('data-reload-on-success') == '1' 20 20 resetScroll = event.target.getAttribute('data-reload-reset-scroll') == '1' 21 21 22 - $(document).one 'turbolinks:load', showPopup 22 + $(document).one 'turbo:load', showPopup 23 23 reloadPage(!resetScroll) 24 24 else 25 25 showPopup()
+1 -1
resources/js/user-cover-preset-batch-activate/index.ts
··· 15 15 constructor() { 16 16 $(document) 17 17 .on('click', '.js-user-cover-preset-batch-enable', this.handleEvent) 18 - .on('turbolinks:before-cache', this.cleanup); 18 + .on('turbo:before-cache', this.cleanup); 19 19 } 20 20 21 21 private applySelected(active: boolean) {
+1 -1
resources/js/utils/beatmap-helper.ts
··· 151 151 function userRecommendedDifficulty(mode: Ruleset) { 152 152 if (userRecommendedDifficultyCache == null) { 153 153 userRecommendedDifficultyCache = parseJsonNullable('json-recommended-star-difficulty-all') ?? {}; 154 - $(document).one('turbolinks:before-cache', () => { 154 + $(document).one('turbo:before-cache', () => { 155 155 userRecommendedDifficultyCache = null; 156 156 }); 157 157 }
+1 -1
resources/js/utils/legacy-score-helper.ts
··· 11 11 let cache: Partial<Record<string, CacheEntry>> = {}; 12 12 13 13 // reset cache on navigation 14 - document.addEventListener('turbolinks:load', () => { 14 + document.addEventListener('turbo:load', () => { 15 15 cache = {}; 16 16 }); 17 17
+32 -5
resources/js/utils/turbolinks.ts
··· 1 1 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 - import { TurbolinksAction } from 'turbolinks'; 4 + import { VisitOptions } from '@hotwired/turbo'; 5 + import { v4 as uuidv4 } from 'uuid'; 5 6 6 7 export function currentUrl() { 7 8 return window.newUrl ?? document.location; ··· 25 26 26 27 function keepScrollOnLoad() { 27 28 const { pageXOffset, pageYOffset } = window; 28 - $(document).one('turbolinks:load', () => window.scrollTo(pageXOffset, pageYOffset)); 29 + $(document).one('turbo:load', () => window.scrollTo(pageXOffset, pageYOffset)); 29 30 } 30 31 31 - export function navigate(url: string, keepScroll = false, { action }: TurbolinksAction = { action: 'advance' }) { 32 + export function navigate(url: string, keepScroll = false, options?: VisitOptions) { 32 33 if (keepScroll) { 33 34 keepScrollOnLoad(); 34 35 } 35 36 36 - Turbolinks.visit(url, { action }); 37 + Turbo.visit(url, options); 37 38 } 38 39 39 40 export function reloadPage(keepScroll = true) { 40 41 $(document).off('.ujsHideLoadingOverlay'); 41 - Turbolinks.clearCache(); 42 + Turbo.cache.clear(); 42 43 43 44 navigate(currentUrl().href, keepScroll, { action: 'replace' }); 44 45 } 46 + 47 + export function updateHistory(url: string, action: 'push' | 'replace') { 48 + const currentLocation = currentUrl(); 49 + 50 + if (url === currentLocation.href) { 51 + return; 52 + } 53 + if (action === 'push') { 54 + Turbo.session.view.snapshotCache.put( 55 + currentLocation, 56 + Turbo.session.view.snapshot.clone(), 57 + ); 58 + } 59 + 60 + const newLocation = new URL(url, document.baseURI); 61 + 62 + const callback = () => { 63 + Turbo.session.history[action](newLocation, uuidv4()); 64 + Turbo.session.view.lastRenderedLocation = newLocation; 65 + }; 66 + if (action === 'replace' && window.newUrl == null) { 67 + window.setTimeout(callback); 68 + } else { 69 + callback(); 70 + } 71 + }
+1 -7
resources/js/utils/url.ts
··· 5 5 import ChangelogBuild from 'interfaces/changelog-build'; 6 6 import Ruleset from 'interfaces/ruleset'; 7 7 import { route } from 'laroute'; 8 - import { startsWith, unescape } from 'lodash'; 9 - import { TurbolinksLocation } from 'turbolinks'; 8 + import { unescape } from 'lodash'; 10 9 import { generate } from './beatmapset-page-hash'; 11 10 import { currentUrl } from './turbolinks'; 12 11 ··· 36 35 37 36 export function giftSupporterTagUrl(user: { username: string }) { 38 37 return route('store.products.show', { product: 'supporter-tag', target: user.username }); 39 - } 40 - 41 - export function isHTML(location: TurbolinksLocation): boolean { 42 - // Some changelog builds have `.` in their version, failing turbolinks' check. 43 - return location.isHTML() || startsWith(location.getPath(), '/home/changelog/'); 44 38 } 45 39 46 40 // external link
+1 -1
resources/js/wiki-search-controller.ts
··· 50 50 return; 51 51 } 52 52 53 - Turbolinks.visit(route('search', { 53 + Turbo.visit(route('search', { 54 54 mode: 'wiki_page', 55 55 query, 56 56 }));
+6
resources/lang/en/authorization.php
··· 176 176 ], 177 177 ], 178 178 179 + 'room' => [ 180 + 'destroy' => [ 181 + 'not_owner' => 'Only room owner can close it.', 182 + ], 183 + ], 184 + 179 185 'score' => [ 180 186 'pin' => [ 181 187 'disabled_type' => "Can't pin this type of score",
+1
resources/lang/en/forum.php
··· 80 80 'confirm_restore' => 'Really restore topic?', 81 81 'deleted' => 'deleted topic', 82 82 'go_to_latest' => 'view latest post', 83 + 'go_to_unread' => 'view first unread post', 83 84 'has_replied' => 'You have replied to this topic', 84 85 'in_forum' => 'in :forum', 85 86 'latest_post' => ':when by :user',
+1 -1
resources/views/artists/show.blade.php
··· 107 107 @if (count($json['albums']) > 0) 108 108 <div class="artist__links-area artist__links-area--albums"> 109 109 @foreach ($json['albums'] as $album) 110 - <a class="artist-sidebar-album{{$album['is_new'] ? ' artist-sidebar-album--new' : ''}}" href="#album-{{$album['id']}}" data-turbolinks="false"> 110 + <a class="artist-sidebar-album{{$album['is_new'] ? ' artist-sidebar-album--new' : ''}}" href="#album-{{$album['id']}}"> 111 111 <div class="artist-sidebar-album__cover-wrapper"> 112 112 <div class="artist-sidebar-album__glow" style="background-image: url('{{ $album['cover_url'] }}');"></div> 113 113 <img class="artist-sidebar-album__cover" src="{{$album['cover_url']}}">
+1 -1
resources/views/forum/forums/_forum.blade.php
··· 3 3 See the LICENCE file in the repository root for full licence text. 4 4 --}} 5 5 <li class="clickable-row forum-item"> 6 - <div class="forum-item-stripe"><span class="u-relative fas fa-angle-right"></span></div> 6 + <div class="forum-item-stripe"><div class="forum-item-stripe__arrow"></div></div> 7 7 8 8 <div class="forum-item__details"> 9 9 {!! link_to(
+8 -8
resources/views/forum/forums/_topic.blade.php
··· 16 16 " 17 17 data-topic-id="{{ $topic->topic_id }}" 18 18 > 19 - <div class="forum-item-stripe"><span class="u-relative fas fa-angle-right"></span></div> 19 + <div class="forum-item-stripe"><div class="forum-item-stripe__arrow"></div></div> 20 20 21 21 <div class="forum-topic-entry__col forum-topic-entry__col--icon"> 22 22 @if (isset($topicReplyStatus[$topic->getKey()])) ··· 24 24 @endif 25 25 26 26 <a 27 - class=" 28 - forum-topic-entry__icon 29 - {{ $isRead ? '' : 'forum-topic-entry__icon--unread' }} 30 - {{ $topic->isLocked() ? 'forum-topic-entry__icon--small' : '' }} 31 - " 32 - href="{{ route("forum.topics.show", $topic->topic_id) }}" 27 + class="{{ class_with_modifiers('forum-topic-entry__icon', [ 28 + 'unread' => !$isRead, 29 + 'small' => $topic->isLocked(), 30 + ]) }}" 31 + href="{{ post_url($topic->getKey(), $isRead ? 'latest' : 'unread', false) }}" 32 + title="{{ osu_trans($isRead ? 'forum.topic.go_to_latest' : 'forum.topic.go_to_unread') }}" 33 33 > 34 34 <span> 35 35 <i class=" ··· 151 151 152 152 <a 153 153 class="forum-topic-entry__col forum-topic-entry__col--last-link" 154 - href="{{ post_url($topic->topic_id, "unread", false) }}" 154 + href="{{ post_url($topic->getKey(), 'latest', false) }}" 155 155 title="{{ osu_trans("forum.topic.go_to_latest") }}" 156 156 > 157 157 <i class="fas fa-chevron-right"></i>
+1 -1
resources/views/home/landing.blade.php
··· 46 46 47 47 </nav> 48 48 49 - <div class="js-nav-data" id="nav-data-landing" data-turbolinks-permanent></div> 49 + <div class="js-nav-data" id="nav-data-landing" data-turbo-permanent></div> 50 50 @include('layout._popup_login', ['modifiers' => ['landing']]) 51 51 52 52 <div class="osu-page">
+1 -1
resources/views/home/search.blade.php
··· 26 26 autofocus 27 27 class="search-header__input js-search--input" 28 28 data-search-current="{{ $allSearch->getRawQuery() }}" 29 - data-turbolinks-permanent 29 + data-turbo-permanent 30 30 id="search-input" 31 31 name="query" 32 32 placeholder="{{ osu_trans('home.search.placeholder') }}"
+15 -4
resources/views/layout/_current_user.blade.php
··· 3 3 See the LICENCE file in the repository root for full licence text. 4 4 --}} 5 5 @php 6 - $user = auth()->user(); 6 + $currentUser ??= Auth::user(); 7 7 8 - $userJson = $user === null 8 + $currentUserJson = $currentUser === null 9 9 ? '{}' 10 - : json_encode(json_item($user, new App\Transformers\CurrentUserTransformer())); 10 + : json_encode(json_item($currentUser, new App\Transformers\CurrentUserTransformer())); 11 11 @endphp 12 12 <script id="json-current-user" type="application/json"> 13 - {!! $userJson !!} 13 + {!! $currentUserJson !!} 14 + </script> 15 + <script> 16 + {{-- 17 + Set current user on first page load. Further updates are done in 18 + reactTurbolinks before the new page is rendered. 19 + This needs to be fired before everything else (turbo:load etc). 20 + --}} 21 + if (!osuCore.firstCurrentUserSet) { 22 + osuCore.firstCurrentUserSet = true; 23 + osuCore.updateCurrentUser(); 24 + } 14 25 </script>
+1 -1
resources/views/layout/_global_variables.blade.php
··· 2 2 Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 3 3 See the LICENCE file in the repository root for full licence text. 4 4 --}} 5 - <script data-turbolinks-eval="always"> 5 + <script data-turbo-eval="always"> 6 6 var csrf = "{{ csrf_token() }}"; 7 7 var canonicalUrl = "{{ $canonicalUrl ?? '' }}"; 8 8 </script>
+4 -4
resources/views/layout/_header_mobile.blade.php
··· 79 79 <a 80 80 class="mobile-menu-tab js-click-menu js-react--chat-icon" 81 81 data-click-menu-target="mobile-chat-notification" 82 - data-turbolinks-permanent 82 + data-turbo-permanent 83 83 data-type='mobile' 84 84 id="notification-widget-chat-icon-mobile" 85 85 href="{{ route('chat.index') }}" ··· 93 93 <a 94 94 class="mobile-menu-tab js-click-menu js-react--main-notification-icon" 95 95 data-click-menu-target="mobile-notification" 96 - data-turbolinks-permanent 96 + data-turbo-permanent 97 97 data-type='mobile' 98 98 id="notification-widget-icon-mobile" 99 99 href="{{ route('notifications.index') }}" ··· 123 123 data-click-menu-id="mobile-chat-notification" 124 124 data-notification-widget="{{ json_encode(['only' => 'channel']) }}" 125 125 data-visibility="hidden" 126 - data-turbolinks-permanent 126 + data-turbo-permanent 127 127 id="notification-widget-chat-mobile" 128 128 ></div> 129 129 ··· 132 132 data-click-menu-id="mobile-notification" 133 133 data-notification-widget="{{ json_encode(['excludes' => ['channel']]) }}" 134 134 data-visibility="hidden" 135 - data-turbolinks-permanent 135 + data-turbo-permanent 136 136 id="notification-widget-mobile" 137 137 ></div> 138 138 @endif
+4 -4
resources/views/layout/_nav2.blade.php
··· 99 99 <a 100 100 class="nav-button nav-button--notifications js-click-menu js-react--chat-icon" 101 101 data-click-menu-target="nav2-chat-notification-widget" 102 - data-turbolinks-permanent 102 + data-turbo-permanent 103 103 id="notification-widget-chat-icon" 104 104 href="{{ route('chat.index') }}" 105 105 > ··· 113 113 data-click-menu-id="nav2-chat-notification-widget" 114 114 data-visibility="hidden" 115 115 data-notification-widget="{{ json_encode(['extraClasses' => 'js-nav2--centered-popup hidden', 'only' => 'channel']) }}" 116 - data-turbolinks-permanent 116 + data-turbo-permanent 117 117 id="notification-widget-chat" 118 118 ></div> 119 119 120 120 <a 121 121 class="nav-button nav-button--notifications js-click-menu js-react--main-notification-icon" 122 122 data-click-menu-target="nav2-notification-widget" 123 - data-turbolinks-permanent 123 + data-turbo-permanent 124 124 id="notification-widget-icon" 125 125 href="{{ route('notifications.index') }}" 126 126 > ··· 134 134 data-click-menu-id="nav2-notification-widget" 135 135 data-visibility="hidden" 136 136 data-notification-widget="{{ json_encode(['extraClasses' => 'js-nav2--centered-popup hidden', 'excludes' => ['channel']]) }}" 137 - data-turbolinks-permanent 137 + data-turbo-permanent 138 138 id="notification-widget" 139 139 ></div> 140 140 </div>
+11 -10
resources/views/layout/metadata.blade.php
··· 23 23 <meta name="keywords" content="osu, peppy, ouendan, elite, beat, agents, ds, windows, game, taiko, tatsujin, simulator, sim, xna, ddr, beatmania, osu!, osume"> 24 24 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 25 25 26 + <meta name="turbo-cache-control" content="no-preview"> 27 + <meta name="turbo-prefetch" content="false"> 28 + 26 29 <link rel="search" type="application/opensearchdescription+xml" title="osu! search" href="{{ $appUrl }}/opensearch.xml"> 27 30 28 31 <meta property="og:site_name" content="osu!"> ··· 48 51 49 52 <meta name="csrf-param" content="_token"> 50 53 <meta name="csrf-token" content="{{ $currentUser === null ? '' : csrf_token() }}"> 51 - 52 - <meta name="turbolinks-cache-control" content="no-preview"> 53 54 54 55 @switch($currentLocale) 55 56 @case('vi') ··· 84 85 @break 85 86 @endswitch 86 87 87 - <link rel="stylesheet" media="all" href="{{ unmix('css/app.css') }}" data-turbolinks-track="reload"> 88 + <link rel="stylesheet" media="all" href="{{ unmix('css/app.css') }}" data-turbo-track="reload"> 88 89 89 90 <script> 90 91 var currentLocale = {!! json_encode($currentLocale) !!}; ··· 92 93 var experimentalHost = {!! json_encode(osu_url('experimental_host')) !!} 93 94 </script> 94 95 95 - <script src="{{ unmix('js/runtime.js') }}" data-turbolinks-track="reload"></script> 96 - <script src="{{ unmix('js/vendor.js') }}" data-turbolinks-track="reload"></script> 96 + <script src="{{ unmix('js/runtime.js') }}" data-turbo-eval="false"></script> 97 + <script src="{{ unmix('js/vendor.js') }}" data-turbo-eval="false"></script> 97 98 98 - <script src="{{ unmix("js/locales/{$currentLocale}.js") }}" data-turbolinks-track="reload"></script> 99 + <script src="{{ unmix("js/locales/{$currentLocale}.js") }}" data-turbo-eval="false"></script> 99 100 @if ($fallbackLocale !== $currentLocale) 100 - <script src="{{ unmix("js/locales/{$fallbackLocale}.js") }}" data-turbolinks-track="reload"></script> 101 + <script src="{{ unmix("js/locales/{$fallbackLocale}.js") }}" data-turbo-eval="false"></script> 101 102 @endif 102 103 103 - <script src="{{ unmix('js/commons.js') }}" data-turbolinks-track="reload"></script> 104 - <script src="{{ unmix('js/app.js') }}" data-turbolinks-track="reload"></script> 104 + <script src="{{ unmix('js/commons.js') }}" data-turbo-eval="false"></script> 105 + <script src="{{ unmix('js/app.js') }}" data-turbo-eval="false"></script> 105 106 106 107 <script 107 108 src="{{ unmix("js/moment-locales/{$currentLocaleMeta->moment()}.js") }}" 108 - data-turbolinks-track="reload" 109 + data-turbo-eval="false" 109 110 ></script> 110 111 111 112 @if (isset($atom))
+3 -4
resources/views/layout/ujs-redirect.blade.php
··· 2 2 Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 3 3 See the LICENCE file in the repository root for full licence text. 4 4 --}} 5 - ;(function() { 6 - $(document).off(".ujsHideLoadingOverlay") 7 - Turbolinks.visit({!! json_encode($url) !!}) 8 - }).call(this); 5 + $(document).off('.ujsHideLoadingOverlay'); 6 + Turbo.cache.clear(); 7 + Turbo.visit({!! json_encode($url) !!});
+2 -2
resources/views/master.blade.php
··· 115 115 </div> 116 116 </div> 117 117 118 - <div id="main-player" class="audio-player-floating" data-turbolinks-permanent> 118 + <div id="main-player" class="audio-player-floating" data-turbo-permanent> 119 119 <div class="js-audio--main"></div> 120 120 <div class="js-sync-height--target" data-sync-height-id="permanent-fixed-footer"></div> 121 121 </div> ··· 125 125 - less/bem/estimate-min-lines.less (styling) 126 126 - views/master.blade.php (placeholder) 127 127 --}} 128 - <div id="estimate-min-lines" class="estimate-min-lines" data-turbolinks-permanent> 128 + <div id="estimate-min-lines" class="estimate-min-lines" data-turbo-permanent> 129 129 <div class="estimate-min-lines__content js-estimate-min-lines"></div> 130 130 </div> 131 131 @include("layout._global_variables")
-1
resources/views/password_reset/index.blade.php
··· 22 22 <form 23 23 action="{{ route('password-reset') }}" 24 24 class="password-reset js-form-error" 25 - data-reload-on-success="1" 26 25 data-remote 27 26 data-skip-ajax-error-popup="1" 28 27 method="POST"
+21 -16
resources/views/user_cover_presets/index.blade.php
··· 89 89 90 90 <div> 91 91 <p> 92 - <button 93 - class="btn-osu-big btn-osu-big--rounded-small" 94 - data-url="{{ route('user-cover-presets.update', [ 92 + <form 93 + action="{{ route('user-cover-presets.update', [ 95 94 'user_cover_preset' => $item->getKey(), 96 95 'active' => $item->active ? '0' : '1', 97 96 ]) }}" 98 - data-method="PUT" 97 + class="u-contents" 99 98 data-reload-on-success="1" 100 - data-remote="1" 101 - title="{{ osu_trans('user_cover_presets.index.item.'.( 102 - $isActive ? 'click_to_disable' : 'click_to_enable' 103 - )) }}" 99 + method="POST" 104 100 > 105 - @if ($isActive) 106 - <span class="fas fa-circle"></span> 107 - {{ osu_trans('user_cover_presets.index.item.enabled') }} 108 - @else 109 - <span class="far fa-circle"></span> 110 - {{ osu_trans('user_cover_presets.index.item.disabled') }} 111 - @endif 112 - </button> 101 + <input type="hidden" name="_method" value="PUT" /> 102 + <button 103 + class="btn-osu-big btn-osu-big--rounded-small" 104 + title="{{ osu_trans('user_cover_presets.index.item.'.( 105 + $isActive ? 'click_to_disable' : 'click_to_enable' 106 + )) }}" 107 + > 108 + @if ($isActive) 109 + <span class="fas fa-circle"></span> 110 + {{ osu_trans('user_cover_presets.index.item.enabled') }} 111 + @else 112 + <span class="far fa-circle"></span> 113 + {{ osu_trans('user_cover_presets.index.item.disabled') }} 114 + @endif 115 + </button> 116 + </form> 113 117 </p> 114 118 <p> 115 119 <form ··· 117 121 enctype="multipart/form-data" 118 122 method="POST" 119 123 class="user-cover-preset-replace" 124 + data-reload-on-success="1" 120 125 > 121 126 @csrf 122 127 <input type="hidden" name="_method" value="PUT" />
+2
resources/views/vendor/passport/authorize.blade.php
··· 90 90 <div class="dialog-form__row dialog-form__row--buttons"> 91 91 <form 92 92 action="{{ route('oauth.authorizations.authorize') }}" 93 + data-turbo="false" 93 94 method="POST" 94 95 > 95 96 @csrf ··· 100 101 101 102 <form 102 103 action="{{ route('oauth.authorizations.authorize') }}" 104 + data-turbo="false" 103 105 method="POST" 104 106 > 105 107 @csrf
+1 -1
routes/web.php
··· 495 495 }); 496 496 }); 497 497 498 - Route::apiResource('rooms', 'Multiplayer\RoomsController', ['only' => ['index', 'show', 'store']]); 498 + Route::apiResource('rooms', 'Multiplayer\RoomsController', ['only' => ['index', 'show', 'store', 'destroy']]); 499 499 500 500 Route::apiResource('seasonal-backgrounds', 'SeasonalBackgroundsController', ['only' => ['index']]); 501 501
+88
tests/Controllers/Multiplayer/RoomsControllerTest.php
··· 429 429 $this->assertSame($initialUserChannelCount + 1, UserChannel::count()); 430 430 } 431 431 432 + public function testDestroy() 433 + { 434 + $start = now(); 435 + $end = $start->clone()->addMinutes(60); 436 + $room = Room::factory()->create([ 437 + 'starts_at' => $start, 438 + 'ends_at' => $end, 439 + 'type' => Room::PLAYLIST_TYPE, 440 + ]); 441 + $end = $room->ends_at; // assignment truncates fractional second part, so refetch here 442 + $url = route('api.rooms.destroy', ['room' => $room]); 443 + 444 + $this->actAsScopedUser($room->host); 445 + $this 446 + ->delete($url) 447 + ->assertSuccessful(); 448 + 449 + $room->refresh(); 450 + $this->assertLessThan($end, $room->ends_at); 451 + } 452 + 453 + public function testDestroyCannotBeCalledOnRealtimeRoom() 454 + { 455 + $start = now(); 456 + $end = $start->clone()->addMinutes(60); 457 + $room = Room::factory()->create([ 458 + 'starts_at' => $start, 459 + 'ends_at' => $end, 460 + 'type' => Room::REALTIME_DEFAULT_TYPE, 461 + ]); 462 + $end = $room->ends_at; // assignment truncates fractional second part, so refetch here 463 + $url = route('api.rooms.destroy', ['room' => $room]); 464 + 465 + $this->actAsScopedUser($room->host); 466 + $this 467 + ->delete($url) 468 + ->assertStatus(422); 469 + 470 + $room->refresh(); 471 + $this->assertEquals($end, $room->ends_at); 472 + } 473 + 474 + public function testDestroyCannotBeCalledByAnotherUser() 475 + { 476 + $requester = User::factory()->create(); 477 + $owner = User::factory()->create(); 478 + $start = now(); 479 + $end = $start->clone()->addMinutes(60); 480 + $room = Room::factory()->create([ 481 + 'user_id' => $owner->getKey(), 482 + 'starts_at' => $start, 483 + 'ends_at' => $end, 484 + 'type' => Room::PLAYLIST_TYPE, 485 + ]); 486 + $url = route('api.rooms.destroy', ['room' => $room]); 487 + $end = $room->ends_at; // assignment truncates fractional second part, so refetch here 488 + 489 + $this->actAsScopedUser($requester); 490 + $this 491 + ->delete($url) 492 + ->assertStatus(403); 493 + 494 + $room->refresh(); 495 + $this->assertEquals($end, $room->ends_at); 496 + } 497 + 498 + public function testDestroyCannotBeCalledAfterGracePeriod() 499 + { 500 + $start = now(); 501 + $end = $start->clone()->addMinutes(60); 502 + $room = Room::factory()->create([ 503 + 'starts_at' => $start, 504 + 'ends_at' => $end, 505 + 'type' => Room::PLAYLIST_TYPE, 506 + ]); 507 + $url = route('api.rooms.destroy', ['room' => $room]); 508 + $end = $room->ends_at; // assignment truncates fractional second part, so refetch here 509 + 510 + $this->actAsScopedUser($room->host); 511 + $this->travelTo($start->addMinutes(6)); 512 + $this 513 + ->delete($url) 514 + ->assertStatus(422); 515 + 516 + $room->refresh(); 517 + $this->assertEquals($end, $room->ends_at); 518 + } 519 + 432 520 public static function dataProviderForTestStoreWithInvalidPlayableMods(): array 433 521 { 434 522 $ret = [];
+17 -23
tests/TestCase.php
··· 152 152 /** 153 153 * Act as a User with OAuth scope permissions. 154 154 */ 155 - protected function actAsScopedUser(?User $user, ?array $scopes = ['*'], ?Client $client = null): void 155 + protected function actAsScopedUser(?User $user, ?array $scopes = ['*'], ?Client $client = null): static 156 156 { 157 - $this->actingWithToken($this->createToken( 157 + return $this->actingWithToken($this->createToken( 158 158 $user, 159 159 $scopes, 160 160 $client ?? Client::factory()->create(), 161 161 )); 162 162 } 163 163 164 - protected function actAsUser(?User $user, bool $verified = false, $driver = null) 164 + protected function actAsUser(?User $user, bool $verified = false, $driver = null): static 165 165 { 166 - if ($user === null) { 167 - return; 166 + if ($user !== null) { 167 + $this->be($user, $driver)->withSession(['verified' => $verified]); 168 168 } 169 169 170 - $this->be($user, $driver); 171 - 172 - $this->withSession(['verified' => $verified]); 170 + return $this; 173 171 } 174 172 175 173 /** ··· 179 177 * @param string $driver Auth driver to use. 180 178 * @return void 181 179 */ 182 - protected function actAsUserWithToken(Token $token, $driver = null) 180 + protected function actAsUserWithToken(Token $token, $driver = null): static 183 181 { 184 182 $guard = app('auth')->guard($driver); 185 183 $user = $token->getResourceOwner(); 186 184 187 - if ($user !== null) { 188 - // guard doesn't accept null user. 185 + if ($user === null) { 186 + $guard->logout(); 187 + } else { 189 188 $guard->setUser($user); 190 189 $user->withAccessToken($token); 191 190 } ··· 196 195 request()->attributes->set(AuthApi::REQUEST_OAUTH_TOKEN_KEY, $token); 197 196 198 197 app('auth')->shouldUse($driver); 199 - } 200 - 201 - protected function actingAsVerified($user) 202 - { 203 - $this->actAsUser($user, true); 204 198 205 199 return $this; 206 200 } 207 201 208 - protected function actingWithToken($token) 202 + protected function actingAsVerified($user): static 209 203 { 210 - $this->actAsUserWithToken($token); 211 - 212 - $encodedToken = EncodeToken::encodeAccessToken($token); 204 + return $this->actAsUser($user, true); 205 + } 213 206 214 - return $this->withHeaders([ 215 - 'Authorization' => "Bearer {$encodedToken}", 216 - ]); 207 + protected function actingWithToken($token): static 208 + { 209 + return $this->actAsUserWithToken($token) 210 + ->withToken(EncodeToken::encodeAccessToken($token)); 217 211 } 218 212 219 213 protected function assertEqualsUpToOneSecond(CarbonInterface $expected, CarbonInterface $actual): void
+13 -2
tests/api_routes.json
··· 1005 1005 ] 1006 1006 }, 1007 1007 { 1008 + "uri": "api/v2/rooms/{room}", 1009 + "methods": [ 1010 + "DELETE" 1011 + ], 1012 + "controller": "App\\Http\\Controllers\\Multiplayer\\RoomsController@destroy", 1013 + "middlewares": [ 1014 + "App\\Http\\Middleware\\ThrottleRequests:1200,1,api:", 1015 + "App\\Http\\Middleware\\RequireScopes", 1016 + "Illuminate\\Auth\\Middleware\\Authenticate" 1017 + ], 1018 + "scopes": [] 1019 + }, 1020 + { 1008 1021 "uri": "api/v2/seasonal-backgrounds", 1009 1022 "methods": [ 1010 1023 "GET", ··· 1028 1041 "App\\Http\\Middleware\\ThrottleRequests:1200,1,api:", 1029 1042 "App\\Http\\Middleware\\RequireScopes", 1030 1043 "App\\Http\\Middleware\\ThrottleRequests:10,1,api-scores-download:", 1031 - "Illuminate\\Auth\\Middleware\\Authenticate", 1032 1044 "App\\Http\\Middleware\\RequireScopes:public" 1033 1045 ], 1034 1046 "scopes": [ ··· 1046 1058 "App\\Http\\Middleware\\ThrottleRequests:1200,1,api:", 1047 1059 "App\\Http\\Middleware\\RequireScopes", 1048 1060 "App\\Http\\Middleware\\ThrottleRequests:10,1,api-scores-download:", 1049 - "Illuminate\\Auth\\Middleware\\Authenticate", 1050 1061 "App\\Http\\Middleware\\RequireScopes:public" 1051 1062 ], 1052 1063 "scopes": [
+7 -8
webpack.config.js
··· 9 9 const path = require('path'); 10 10 11 11 const Autoprefixer = require('autoprefixer'); 12 - const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 13 12 const CopyPlugin = require('copy-webpack-plugin'); 14 13 const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); 15 14 const dotenv = require('dotenv'); ··· 93 92 moment: 'moment', 94 93 React: 'react', 95 94 ReactDOM: 'react-dom', 96 - Turbolinks: 'turbolinks', 97 95 }), 98 96 new webpack.DefinePlugin({ 99 97 'process.env.DOCS_URL': JSON.stringify(process.env.DOCS_URL || 'https://docs.ppy.sh'), ··· 131 129 132 130 // TODO: should have a different flag for this 133 131 if (!inProduction) { 132 + const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 134 133 plugins.push(new CleanWebpackPlugin()); 135 - } 136 134 137 - const notifierConfigPath = resolvePath('.webpack-build-notifier-config.js'); 138 - if (fs.existsSync(notifierConfigPath)) { 139 - const WebpackBuildNotifierPlugin = require('webpack-build-notifier'); 140 - plugins.push(new WebpackBuildNotifierPlugin(require(notifierConfigPath))); 135 + const notifierConfigPath = resolvePath('.webpack-build-notifier-config.js'); 136 + if (fs.existsSync(notifierConfigPath)) { 137 + const WebpackBuildNotifierPlugin = require('webpack-build-notifier'); 138 + plugins.push(new WebpackBuildNotifierPlugin(require(notifierConfigPath))); 139 + } 141 140 } 142 141 143 142 // #endregion ··· 206 205 modules: [ 207 206 resolvePath('resources/builds'), 208 207 resolvePath('resources/js'), 209 - resolvePath('node_modules'), 208 + 'node_modules', 210 209 ], 211 210 plugins: [new TsconfigPathsPlugin()], 212 211 };
+47 -146
yarn.lock
··· 254 254 resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.9.0.tgz#1aa5c59efb1b8c6eb6277d1e3e8c8f31998b8c8e" 255 255 integrity sha512-g795BBEzM/Hq2SYNPm/NQTIp3IWd4eXSH0ds87Na2jnrAUFX3wkyZAI4Gwj9DOaWMuz2/01i8oWI7P7T/XLkhg== 256 256 257 + "@hotwired/turbo@^8.0.12": 258 + version "8.0.12" 259 + resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-8.0.12.tgz#50aa8345d7f62402680c6d2d9814660761837001" 260 + integrity sha512-l3BiQRkD7qrnQv6ms6sqPLczvwbQpXt5iAVwjDvX0iumrz6yEonQkNAzNjeDX25/OJMFDTxpHjkJZHGpM9ikWw== 261 + 257 262 "@isaacs/cliui@^8.0.2": 258 263 version "8.0.2" 259 264 resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" ··· 322 327 resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" 323 328 integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== 324 329 325 - "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": 326 - version "0.3.19" 327 - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" 328 - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== 329 - dependencies: 330 - "@jridgewell/resolve-uri" "^3.1.0" 331 - "@jridgewell/sourcemap-codec" "^1.4.14" 332 - 333 - "@jridgewell/trace-mapping@^0.3.20": 330 + "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.9": 334 331 version "0.3.25" 335 332 resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" 336 333 integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== ··· 391 388 version "0.2.0" 392 389 resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" 393 390 integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== 394 - 395 - "@types/anymatch@*": 396 - version "1.3.1" 397 - resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" 398 - integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== 399 391 400 392 "@types/autosize@^4.0.1": 401 393 version "4.0.1" ··· 652 644 integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ== 653 645 654 646 "@types/glob@^7.1.1": 655 - version "7.1.3" 656 - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" 657 - integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== 647 + version "7.2.0" 648 + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" 649 + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== 658 650 dependencies: 659 651 "@types/minimatch" "*" 660 652 "@types/node" "*" ··· 665 657 integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== 666 658 dependencies: 667 659 "@types/unist" "*" 660 + 661 + "@types/hotwired__turbo@^8.0.2": 662 + version "8.0.2" 663 + resolved "https://registry.yarnpkg.com/@types/hotwired__turbo/-/hotwired__turbo-8.0.2.tgz#db683460bb32a21715a5cf1f07a7de81d1c3124a" 664 + integrity sha512-fFWI/JNSTVKTPliSOV4fdeC3Kt3FUTbRYkvtF7QPCkqR51+AJWIiX0T5sJXwUnjL9j43tzfBXPZ2jEsBqw8/Bg== 668 665 669 666 "@types/is-hotkey@^0.1.1": 670 667 version "0.1.1" ··· 746 743 "@types/unist" "*" 747 744 748 745 "@types/minimatch@*": 749 - version "3.0.3" 750 - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" 751 - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== 746 + version "5.1.2" 747 + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" 748 + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== 752 749 753 750 "@types/ms@*": 754 751 version "0.7.31" ··· 808 805 resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" 809 806 integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== 810 807 811 - "@types/source-list-map@*": 812 - version "0.1.2" 813 - resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" 814 - integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== 815 - 816 - "@types/tapable@*": 817 - version "1.0.6" 818 - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74" 819 - integrity sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA== 820 - 821 808 "@types/timeago@^1.6.0": 822 809 version "1.6.0" 823 810 resolved "https://registry.yarnpkg.com/@types/timeago/-/timeago-1.6.0.tgz#67c9c5db18e49cc6e47bbaa096dbc4721b79f295" ··· 825 812 dependencies: 826 813 "@types/jquery" "*" 827 814 828 - "@types/uglify-js@*": 829 - version "3.9.3" 830 - resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.9.3.tgz#d94ed608e295bc5424c9600e6b8565407b6b4b6b" 831 - integrity sha512-KswB5C7Kwduwjj04Ykz+AjvPcfgv/37Za24O2EDzYNbwyzOo8+ydtvzUfZ5UMguiVu29Gx44l1A6VsPPcmYu9w== 832 - dependencies: 833 - source-map "^0.6.1" 834 - 835 815 "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.6": 836 816 version "2.0.6" 837 817 resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" 838 818 integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== 839 819 840 - "@types/webpack-sources@*": 841 - version "1.4.2" 842 - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-1.4.2.tgz#5d3d4dea04008a779a90135ff96fb5c0c9e6292c" 843 - integrity sha512-77T++JyKow4BQB/m9O96n9d/UUHWLQHlcqXb9Vsf4F1+wKNrrlWNFPDLKNT92RJnCSL6CieTc+NDXtCVZswdTw== 844 - dependencies: 845 - "@types/node" "*" 846 - "@types/source-list-map" "*" 847 - source-map "^0.7.3" 848 - 849 - "@types/webpack@^4.4.31": 850 - version "4.41.22" 851 - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.22.tgz#ff9758a17c6bd499e459b91e78539848c32d0731" 852 - integrity sha512-JQDJK6pj8OMV9gWOnN1dcLCyU9Hzs6lux0wBO4lr1+gyEhIBR9U3FMrz12t2GPkg110XAxEAw2WHF6g7nZIbRQ== 853 - dependencies: 854 - "@types/anymatch" "*" 855 - "@types/node" "*" 856 - "@types/tapable" "*" 857 - "@types/uglify-js" "*" 858 - "@types/webpack-sources" "*" 859 - source-map "^0.6.0" 860 - 861 820 "@types/yargs-parser@*": 862 821 version "21.0.0" 863 822 resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" ··· 1699 1658 union-value "^1.0.0" 1700 1659 unset-value "^1.0.0" 1701 1660 1702 - call-bind@^1.0.0, call-bind@^1.0.2: 1703 - version "1.0.2" 1704 - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" 1705 - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 1706 - dependencies: 1707 - function-bind "^1.1.1" 1708 - get-intrinsic "^1.0.2" 1709 - 1710 - call-bind@^1.0.7: 1661 + call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.7: 1711 1662 version "1.0.7" 1712 1663 resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" 1713 1664 integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== ··· 1833 1784 isobject "^3.0.0" 1834 1785 static-extend "^0.1.1" 1835 1786 1836 - clean-webpack-plugin@^3.0.0: 1837 - version "3.0.0" 1838 - resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz#a99d8ec34c1c628a4541567aa7b457446460c62b" 1839 - integrity sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A== 1787 + clean-webpack-plugin@^4.0.0: 1788 + version "4.0.0" 1789 + resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz#72947d4403d452f38ed61a9ff0ada8122aacd729" 1790 + integrity sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w== 1840 1791 dependencies: 1841 - "@types/webpack" "^4.4.31" 1842 1792 del "^4.1.1" 1843 1793 1844 1794 clipboard-polyfill@^2.3.0: ··· 2554 2504 dependencies: 2555 2505 ms "^2.1.1" 2556 2506 2557 - debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: 2558 - version "4.3.4" 2559 - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 2560 - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 2561 - dependencies: 2562 - ms "2.1.2" 2563 - 2564 - debug@~4.3.4: 2507 + debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4: 2565 2508 version "4.3.5" 2566 2509 resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" 2567 2510 integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== ··· 3487 3430 resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 3488 3431 integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 3489 3432 3490 - function-bind@^1.1.1: 3491 - version "1.1.1" 3492 - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 3493 - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 3494 - 3495 - function-bind@^1.1.2: 3433 + function-bind@^1.1.1, function-bind@^1.1.2: 3496 3434 version "1.1.2" 3497 3435 resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 3498 3436 integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== ··· 3517 3455 resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 3518 3456 integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 3519 3457 3520 - get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: 3521 - version "1.1.1" 3522 - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" 3523 - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== 3524 - dependencies: 3525 - function-bind "^1.1.1" 3526 - has "^1.0.3" 3527 - has-symbols "^1.0.1" 3528 - 3529 - get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: 3458 + get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: 3530 3459 version "1.2.4" 3531 3460 resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" 3532 3461 integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== ··· 3657 3586 globby@^6.1.0: 3658 3587 version "6.1.0" 3659 3588 resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" 3660 - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= 3589 + integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== 3661 3590 dependencies: 3662 3591 array-union "^1.0.1" 3663 3592 glob "^7.0.3" ··· 3727 3656 resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" 3728 3657 integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== 3729 3658 3730 - has-symbols@^1.0.1, has-symbols@^1.0.2: 3731 - version "1.0.2" 3732 - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" 3733 - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== 3734 - 3735 - has-symbols@^1.0.3: 3659 + has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: 3736 3660 version "1.0.3" 3737 3661 resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" 3738 3662 integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== ··· 4451 4375 dependencies: 4452 4376 jquery ">=1.8.0 <4.0.0" 4453 4377 4454 - jquery-ujs@^1.2.2: 4455 - version "1.2.2" 4456 - resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.2.tgz#6a8ef1020e6b6dda385b90a4bddc128c21c56397" 4457 - integrity sha1-ao7xAg5rbdo4W5CkvdwSjCHFY5c= 4458 - dependencies: 4459 - jquery ">=1.8.0" 4378 + jquery-ujs@^1.2.3: 4379 + version "1.2.3" 4380 + resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.3.tgz#dcac6026ab7268e5ee41faf9d31c997cd4ddd603" 4381 + integrity sha512-59wvfx5vcCTHMeQT1/OwFiAj+UffLIwjRIoXdpO7Z7BCFGepzq9T9oLVeoItjTqjoXfUrHJvV7QU6pUR+UzOoA== 4460 4382 4461 4383 jquery.scrollto@^2.1.2: 4462 4384 version "2.1.2" ··· 4465 4387 dependencies: 4466 4388 jquery ">=1.8" 4467 4389 4468 - "jquery@>=1.5.0 <4.0", jquery@>=1.6.0, jquery@>=1.8, jquery@>=1.8.0, "jquery@>=1.8.0 <4.0.0", jquery@^3.5.0: 4469 - version "3.6.0" 4470 - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" 4471 - integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== 4390 + "jquery@>=1.5.0 <4.0", jquery@>=1.6.0, jquery@>=1.8, "jquery@>=1.8.0 <4.0.0", jquery@^3.5.0: 4391 + version "3.7.1" 4392 + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de" 4393 + integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== 4472 4394 4473 4395 "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: 4474 4396 version "4.0.0" ··· 5579 5501 define-property "^0.2.5" 5580 5502 kind-of "^3.0.3" 5581 5503 5582 - object-inspect@^1.11.0, object-inspect@^1.9.0: 5583 - version "1.12.0" 5584 - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" 5585 - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== 5586 - 5587 - object-inspect@^1.13.1: 5504 + object-inspect@^1.11.0, object-inspect@^1.13.1: 5588 5505 version "1.13.2" 5589 5506 resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" 5590 5507 integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== ··· 5873 5790 path-is-inside@^1.0.2: 5874 5791 version "1.0.2" 5875 5792 resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 5876 - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= 5793 + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== 5877 5794 5878 5795 path-key@^2.0.0, path-key@^2.0.1: 5879 5796 version "2.0.1" ··· 5939 5856 pify@^2.0.0: 5940 5857 version "2.3.0" 5941 5858 resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 5942 - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= 5859 + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== 5943 5860 5944 5861 pify@^3.0.0: 5945 5862 version "3.0.0" ··· 5954 5871 pinkie-promise@^2.0.0: 5955 5872 version "2.0.1" 5956 5873 resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 5957 - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= 5874 + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== 5958 5875 dependencies: 5959 5876 pinkie "^2.0.0" 5960 5877 5961 5878 pinkie@^2.0.0: 5962 5879 version "2.0.4" 5963 5880 resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 5964 - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= 5881 + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== 5965 5882 5966 5883 pkg-dir@^2.0.0: 5967 5884 version "2.0.0" ··· 6318 6235 resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" 6319 6236 integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== 6320 6237 6321 - qs@6.13.0: 6238 + qs@6.13.0, qs@^6.11.0: 6322 6239 version "6.13.0" 6323 6240 resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" 6324 6241 integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== 6325 6242 dependencies: 6326 6243 side-channel "^1.0.6" 6327 6244 6328 - qs@^6.11.0: 6329 - version "6.11.2" 6330 - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" 6331 - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== 6332 - dependencies: 6333 - side-channel "^1.0.4" 6334 - 6335 6245 qs@~6.9.7: 6336 6246 version "6.9.7" 6337 6247 resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" ··· 6861 6771 resolved "https://registry.yarnpkg.com/shopify-buy/-/shopify-buy-2.19.0.tgz#5c1e0f9fd0fb91266f467c7a8fca1ec7100d983a" 6862 6772 integrity sha512-XCkQDG9DokhWUiRTOh+6K9I2w3uMys+R1mCt8h3l4le/9TjVxVJ1jbWD7ioyPf1Bc+fPLR6KX62JT1K6NE/S8A== 6863 6773 6864 - side-channel@^1.0.4: 6865 - version "1.0.4" 6866 - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" 6867 - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== 6868 - dependencies: 6869 - call-bind "^1.0.0" 6870 - get-intrinsic "^1.0.2" 6871 - object-inspect "^1.9.0" 6872 - 6873 - side-channel@^1.0.6: 6774 + side-channel@^1.0.4, side-channel@^1.0.6: 6874 6775 version "1.0.6" 6875 6776 resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" 6876 6777 integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== ··· 7513 7414 resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" 7514 7415 integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== 7515 7416 7516 - turbolinks@^5.1.1: 7517 - version "5.2.0" 7518 - resolved "https://registry.yarnpkg.com/turbolinks/-/turbolinks-5.2.0.tgz#e6877a55ea5c1cb3bb225f0a4ae303d6d32ff77c" 7519 - integrity sha512-pMiez3tyBo6uRHFNNZoYMmrES/IaGgMhQQM+VFF36keryjb5ms0XkVpmKHkfW/4Vy96qiGW3K9bz0tF5sK9bBw== 7520 - 7521 7417 twemoji-parser@14.0.0: 7522 7418 version "14.0.0" 7523 7419 resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-14.0.0.tgz#13dabcb6d3a261d9efbf58a1666b182033bf2b62" ··· 7714 7610 version "1.0.1" 7715 7611 resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 7716 7612 integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 7613 + 7614 + uuid@^11.0.3: 7615 + version "11.0.3" 7616 + resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.0.3.tgz#248451cac9d1a4a4128033e765d137e2b2c49a3d" 7617 + integrity sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg== 7717 7618 7718 7619 uuid@^8.3.0: 7719 7620 version "8.3.2"