diff --git a/.env.example b/.env.example index ccd7e54..7608a6c 100644 --- a/.env.example +++ b/.env.example @@ -63,3 +63,9 @@ AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" + +# Jitsi Meet (Video Conferencing) +# Defaults to public instance meet.jit.si if left blank +JITSI_DOMAIN=meet.jit.si +JITSI_APP_ID= +JITSI_APP_SECRET= diff --git a/README.md b/README.md index c8ec098..099cda4 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,15 @@ Short demo on YouTube: [Demo](https://youtu.be/Vk0FuN59XUE) - Detailed activity log timeline for full auditability. - **Document Uploads:** Attach files directly to tasks (currently supporting Images and PDFs). - **Smart Link Previews:** Automatic, rich previews for URLs embedded in task descriptions and comments. +- **Interactive Calendar & Scheduling:** + - Full-featured calendar supporting Month, Week, and Day views. + - Drag-and-drop time range selection to quickly create events. + - Event creation and editing with descriptions, date/time pickers, and attendee assignments. + - Team member invitations with RSVP statuses (Accepted, Declined, Pending) and event privacy/hiding controls. +- **Integrated Video Conferencing (Jitsi Meet):** + - One-click video call generation directly linked to scheduled events. + - Dedicated in-app meeting room view with Jitsi Meet integration. + - Support for custom self-hosted (on-premise) instances or automatic fallback to public servers (`meet.jit.si`). - **Workload Dashboard:** Team workspace overview featuring task metrics, urgent "To Handle Now" tasks, column breakdowns, and a recent activity feed. ## Tech Stack @@ -31,6 +40,7 @@ Short demo on YouTube: [Demo](https://youtu.be/Vk0FuN59XUE) - **Backend:** Laravel 13 (PHP >= 8.4), Inertia.js V3 - **Frontend:** Vue 3 - **Styling:** Tailwind CSS & Shadcn +- **Video Conferencing:** Jitsi Meet - **CI/CD:** GitHub Actions workflow for automated testing, linting and deployment. - **Deployment:** Docker, with a production-ready Dockerfile included in the repository. @@ -94,3 +104,21 @@ Taskly ships with a single-tenant role model. Every account holds one of three * - **Removing & demoting:** privileged users cannot be removed from a team (they always retain access). Demoting an Admin keeps them as an explicit member of the team the demotion happened in, so they don't silently vanish from the member list. - **New teams** are bootstrapped with default columns (To Do, In Progress, Done), matching the seeder. +## Video Conferencing Setup (Jitsi Meet) + +Taskly includes integrated video conferencing for calendar events powered by Jitsi Meet. It works out of the box with zero configuration, while supporting private, on-premise deployments: + +- **Public Fallback (Default):** If `JITSI_DOMAIN` is omitted or left empty, Taskly automatically connects to the public instance (`meet.jit.si`). No API keys or extra configuration are needed. +- **Self-Hosted / On-Premise:** If your organization hosts its own Jitsi Meet server, point Taskly to it by setting `JITSI_DOMAIN` to your instance domain (e.g., `meet.yourcompany.com`). +- **JWT Authentication & Moderation:** For self-hosted instances secured with token authentication (JWT), define `JITSI_APP_ID` and `JITSI_APP_SECRET`. Taskly will automatically issue signed HS256 JWT tokens to grant moderator privileges to the event organizer. + +Add or update these variables in your `.env` file: + +```env +# Jitsi Meet domain (defaults to meet.jit.si if left blank) +JITSI_DOMAIN=meet.jit.si + +# Optional: required only for authenticated / self-hosted Jitsi instances +JITSI_APP_ID= +JITSI_APP_SECRET= +``` \ No newline at end of file diff --git a/app/Http/Controllers/CalendarController.php b/app/Http/Controllers/CalendarController.php new file mode 100644 index 0000000..b34cacc --- /dev/null +++ b/app/Http/Controllers/CalendarController.php @@ -0,0 +1,96 @@ +calendarService->indexData( + $request->user(), + $request->query('start'), + $request->query('end'), + ); + + return Inertia::render('Calendar/Index', [ + 'events' => Inertia::defer(fn () => EventIndexResource::collection($data['events'])->resolve($request)), + 'teamMembers' => $data['teamMembers'], + 'view' => $request->query('view'), + 'start' => $request->query('start'), + 'end' => $request->query('end'), + ]); + } + + public function show(Request $request, Event $event): JsonResponse + { + $this->authorize('view', $event); + + return response()->json( + EventResource::make($this->calendarService->show($event))->resolve($request) + ); + } + + public function store(EventStoreRequest $request): RedirectResponse + { + $this->calendarService->create($request->validated(), $request->user()); + + return back(); + } + + public function update(EventUpdateRequest $request, Event $event): RedirectResponse + { + $this->authorize('update', $event); + + $this->calendarService->update($event, $request->validated()); + + return back(); + } + + public function destroy(Request $request, Event $event): RedirectResponse + { + $this->authorize('delete', $event); + + $this->calendarService->hide($event, $request->user()); + + return back(); + } + + public function respond(EventRespondRequest $request, Event $event): RedirectResponse + { + $this->authorize('respond', $event); + + $this->calendarService->respond($event, $request->user(), $request->validated('response')); + + return back(); + } + + public function room(Request $request, Event $event): Response + { + $this->authorize('room', $event); + + return Inertia::render('Calendar/Room', [ + 'event' => EventResource::make($event->load('organizer:id,name'))->resolve($request), + 'jitsiDomain' => config('services.jitsi.domain'), + 'jwt' => $this->calendarService->generateJitsiToken( + $request->user(), + $event->room_name, + $request->user()->id === $event->organizer_id + ), + ]); + } +} diff --git a/app/Http/Controllers/NotificationController.php b/app/Http/Controllers/NotificationController.php new file mode 100644 index 0000000..01e0626 --- /dev/null +++ b/app/Http/Controllers/NotificationController.php @@ -0,0 +1,41 @@ +json( + NotificationResource::paginated($this->notificationService->paginateFor($request->user()), $request) + ); + } + + public function markAsRead(Request $request, DatabaseNotification $notification): RedirectResponse + { + abort_unless( + $notification->notifiable()->whereKey($request->user()->getKey())->exists(), + 403 + ); + + $notification->markAsRead(); + + return back(); + } + + public function markAllAsRead(Request $request): RedirectResponse + { + $request->user()->unreadNotifications()->update(['read_at' => now()]); + + return back(); + } +} diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index b89b871..e4396ca 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -20,7 +20,7 @@ public function index(Request $request): Response { $tags = $this->tagService->listForTeam($request->user()->team_id); - return Inertia::render('Tags', [ + return Inertia::render('settings/Tags', [ 'tags' => $tags->through( fn (Tag $tag) => (new TagResource($tag))->resolve($request) ), @@ -31,7 +31,7 @@ public function store(TagStoreRequest $request): RedirectResponse { $this->tagService->create($request->validated(), $request->user()); - return to_route('tags.index'); + return to_route('settings.tags.index'); } public function update(TagUpdateRequest $request, Tag $tag): RedirectResponse @@ -40,7 +40,7 @@ public function update(TagUpdateRequest $request, Tag $tag): RedirectResponse $this->tagService->update($tag, $request->validated()); - return to_route('tags.index'); + return to_route('settings.tags.index'); } public function destroy(Request $request, Tag $tag): RedirectResponse @@ -49,6 +49,6 @@ public function destroy(Request $request, Tag $tag): RedirectResponse $this->tagService->delete($tag); - return to_route('tags.index'); + return to_route('settings.tags.index'); } } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 2209441..16ae3db 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -2,12 +2,15 @@ namespace App\Http\Middleware; +use App\Services\NotificationService; use Illuminate\Foundation\Inspiring; use Illuminate\Http\Request; use Inertia\Middleware; class HandleInertiaRequests extends Middleware { + public function __construct(private readonly NotificationService $notificationService) {} + /** * The root template that's loaded on the first page visit. * @@ -50,6 +53,11 @@ public function share(Request $request): array ? $request->user()->accessibleTeamsQuery()->orderBy('name')->get(['id', 'name']) : [], 'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true', + 'notifications' => fn () => [ + 'unreadCount' => $request->user() + ? $this->notificationService->unreadCountFor($request->user()) + : 0, + ], ]; } } diff --git a/app/Http/Requests/Concerns/EventRules.php b/app/Http/Requests/Concerns/EventRules.php new file mode 100644 index 0000000..b24edb2 --- /dev/null +++ b/app/Http/Requests/Concerns/EventRules.php @@ -0,0 +1,29 @@ +> + */ + protected function eventRules(int $teamId): array + { + return [ + 'title' => ['required', 'string', 'max:255'], + 'description' => ['nullable', 'string'], + 'start_at' => ['required', 'date'], + 'end_at' => ['required', 'date', 'after:start_at'], + 'timezone' => ['sometimes', 'string', 'max:50'], + 'has_video' => ['sometimes', 'boolean'], + 'attendee_ids' => ['sometimes', 'array'], + 'attendee_ids.*' => ['integer', Rule::exists('users', 'id')->where( + fn ($query) => $query->where('team_id', $teamId) + )], + ]; + } +} diff --git a/app/Http/Requests/EventRespondRequest.php b/app/Http/Requests/EventRespondRequest.php new file mode 100644 index 0000000..065393e --- /dev/null +++ b/app/Http/Requests/EventRespondRequest.php @@ -0,0 +1,31 @@ +merge([ + 'response' => $this->route('response'), + ]); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return [ + 'response' => ['required', 'in:accepted,declined'], + ]; + } +} diff --git a/app/Http/Requests/EventStoreRequest.php b/app/Http/Requests/EventStoreRequest.php new file mode 100644 index 0000000..15de4c4 --- /dev/null +++ b/app/Http/Requests/EventStoreRequest.php @@ -0,0 +1,22 @@ +|string> + */ + public function rules(): array + { + return $this->eventRules($this->user()?->team_id); + } +} diff --git a/app/Http/Requests/EventUpdateRequest.php b/app/Http/Requests/EventUpdateRequest.php new file mode 100644 index 0000000..89ae04b --- /dev/null +++ b/app/Http/Requests/EventUpdateRequest.php @@ -0,0 +1,25 @@ +|string> + */ + public function rules(): array + { + $event = $this->route('event'); + $teamId = $event?->calendar?->team_id ?? $this->user()?->team_id; + + return $this->eventRules($teamId); + } +} diff --git a/app/Http/Resources/EventIndexResource.php b/app/Http/Resources/EventIndexResource.php new file mode 100644 index 0000000..4a5e2aa --- /dev/null +++ b/app/Http/Resources/EventIndexResource.php @@ -0,0 +1,25 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'title' => $this->title, + 'start_at' => $this->start_at?->toIso8601String(), + 'end_at' => $this->end_at?->toIso8601String(), + 'has_video' => $this->has_video, + ]; + } +} diff --git a/app/Http/Resources/EventResource.php b/app/Http/Resources/EventResource.php new file mode 100644 index 0000000..41a9238 --- /dev/null +++ b/app/Http/Resources/EventResource.php @@ -0,0 +1,40 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'calendar_id' => $this->calendar_id, + 'organizer_id' => $this->organizer_id, + 'title' => $this->title, + 'description' => $this->description, + 'start_at' => $this->start_at?->toIso8601String(), + 'end_at' => $this->end_at?->toIso8601String(), + 'timezone' => $this->timezone, + 'room_name' => $this->room_name, + 'has_video' => $this->has_video, + 'status' => $this->status, + 'organizer' => $this->whenLoaded('organizer', fn () => [ + 'id' => $this->organizer->id, + 'name' => $this->organizer->name, + ]), + 'attendees' => $this->whenLoaded('attendees', fn () => $this->attendees + ->map(fn ($attendee) => [ + 'id' => $attendee->id, + 'name' => $attendee->name, + ])->values()), + ]; + } +} diff --git a/app/Http/Resources/NotificationResource.php b/app/Http/Resources/NotificationResource.php new file mode 100644 index 0000000..dad7d01 --- /dev/null +++ b/app/Http/Resources/NotificationResource.php @@ -0,0 +1,57 @@ + + */ + private const TYPE_ALIASES = [ + EventInvitation::class => 'event_invitation', + ]; + + /** + * Transform a page of notifications into the payload the dropdown loads. + * + * @return array{data: array>, pagination: array{current_page: int, last_page: int, total: int, has_more: bool}} + */ + public static function paginated(LengthAwarePaginator $notifications, Request $request): array + { + return [ + 'data' => self::collection($notifications->items())->resolve($request), + 'pagination' => [ + 'current_page' => $notifications->currentPage(), + 'last_page' => $notifications->lastPage(), + 'total' => $notifications->total(), + 'has_more' => $notifications->hasMorePages(), + ], + ]; + } + + /** + * Transform the resource into an array. + * + * @return array + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'type' => self::TYPE_ALIASES[$this->type] ?? $this->type, + 'data' => $this->data, + 'read_at' => $this->read_at?->toIso8601String(), + 'created_at' => $this->created_at?->toIso8601String(), + ]; + } +} diff --git a/app/Http/Resources/TaskResource.php b/app/Http/Resources/TaskResource.php index 09828d0..dbebf74 100644 --- a/app/Http/Resources/TaskResource.php +++ b/app/Http/Resources/TaskResource.php @@ -127,7 +127,7 @@ public function toArray(Request $request): array 'title' => $this->title, 'description' => $description, 'days_in_column' => $daysInColumn, - 'due_date' => $this->due_date, + 'due_date' => $this->due_date?->toIso8601String(), 'created_by' => $this->created_by, 'assigned_to' => $this->assigned_to, 'creator' => $this->whenLoaded('creator', fn () => [ diff --git a/app/Models/Calendar.php b/app/Models/Calendar.php new file mode 100644 index 0000000..817ea13 --- /dev/null +++ b/app/Models/Calendar.php @@ -0,0 +1,46 @@ +belongsTo(User::class, 'owner_id'); + } + + public function team(): BelongsTo + { + return $this->belongsTo(Team::class); + } + + public function members(): BelongsToMany + { + return $this->belongsToMany(User::class, 'calendar_members') + ->withPivot('role') + ->withTimestamps(); + } + + public function events(): HasMany + { + return $this->hasMany(Event::class); + } +} diff --git a/app/Models/Event.php b/app/Models/Event.php new file mode 100644 index 0000000..34f356a --- /dev/null +++ b/app/Models/Event.php @@ -0,0 +1,75 @@ + */ + use HasFactory, HasUuids; + + /** + * Generate a UUID for the uid column instead of the integer primary key. + * + * @return list + */ + public function uniqueIds(): array + { + return ['uid']; + } + + protected $fillable = [ + 'calendar_id', + 'organizer_id', + 'uid', + 'title', + 'description', + 'start_at', + 'end_at', + 'timezone', + 'has_video', + 'room_name', + 'status', + ]; + + protected function casts(): array + { + return [ + 'start_at' => 'datetime', + 'end_at' => 'datetime', + 'has_video' => 'boolean', + ]; + } + + /** + * Get the calendars this event belongs to. + */ + public function calendar(): BelongsTo + { + return $this->belongsTo(Calendar::class); + } + + /** + * Get the user who organized the event. + */ + public function organizer(): BelongsTo + { + return $this->belongsTo(User::class, 'organizer_id'); + } + + /** + * Get the users invited to the event. + */ + public function attendees(): BelongsToMany + { + return $this->belongsToMany(User::class, 'event_attendees') + ->withPivot(['participation_status', 'responded_at', 'hidden_at']) + ->withTimestamps(); + } +} diff --git a/app/Models/TeamMembership.php b/app/Models/TeamMembership.php index eb1c937..ac17100 100644 --- a/app/Models/TeamMembership.php +++ b/app/Models/TeamMembership.php @@ -2,11 +2,14 @@ namespace App\Models; +use App\Observers\TeamMembershipObserver; use Database\Factories\TeamMembershipFactory; +use Illuminate\Database\Eloquent\Attributes\ObservedBy; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +#[ObservedBy([TeamMembershipObserver::class])] class TeamMembership extends Model { /** @use HasFactory */ diff --git a/app/Models/User.php b/app/Models/User.php index e051706..81f095e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -88,6 +88,26 @@ public function taskComments(): HasMany return $this->hasMany(TaskComment::class); } + /** + * Get the calendars the user is a member of. + */ + public function calendars(): BelongsToMany + { + return $this->belongsToMany(Calendar::class, 'calendar_members') + ->withPivot('role') + ->withTimestamps(); + } + + /** + * Get the events the user attends. + */ + public function attendedEvents(): BelongsToMany + { + return $this->belongsToMany(Event::class, 'event_attendees') + ->withPivot(['participation_status', 'responded_at', 'hidden_at']) + ->withTimestamps(); + } + /** * Determine if the user is an owner. */ diff --git a/app/Notifications/EventInvitation.php b/app/Notifications/EventInvitation.php new file mode 100644 index 0000000..b9e5a2a --- /dev/null +++ b/app/Notifications/EventInvitation.php @@ -0,0 +1,51 @@ + $this->event->id, + 'title' => $this->event->title, + 'description' => $this->event->description, + 'start_time' => $this->event->start_at?->toISOString(), + 'end_time' => $this->event->end_at?->toISOString(), + 'inviter' => $this->event->organizer?->name, + 'has_video' => $this->event->has_video, + 'response' => 'needs_action', + ]; + } + + public function toArray(object $notifiable): array + { + return $this->toDatabase($notifiable); + } + + public function toMail(object $notifiable): MailMessage + { + return (new MailMessage) + ->subject('You are invited to: '.$this->event->title) + ->greeting('Hello '.$notifiable->name.',') + ->line('You have been invited to an event on Taskly.') + ->line($this->event->title) + ->line($this->event->start_at->format('l, F j, Y at g:i A')) + ->action('View invitation', url('/calendar')) + ->line('You can accept or decline the invitation from Taskly.'); + } +} diff --git a/app/Observers/CalendarObserver.php b/app/Observers/CalendarObserver.php new file mode 100644 index 0000000..70283bd --- /dev/null +++ b/app/Observers/CalendarObserver.php @@ -0,0 +1,18 @@ +members()->syncWithoutDetaching([ + $calendar->owner_id => ['role' => 'owner'], + ]); + } +} diff --git a/app/Observers/TeamMembershipObserver.php b/app/Observers/TeamMembershipObserver.php new file mode 100644 index 0000000..2457a38 --- /dev/null +++ b/app/Observers/TeamMembershipObserver.php @@ -0,0 +1,20 @@ + $membership->team_id, 'owner_id' => $membership->user_id], + ['name' => 'My Calendar', 'color' => null], + ); + } +} diff --git a/app/Policies/EventPolicy.php b/app/Policies/EventPolicy.php new file mode 100644 index 0000000..1d3b742 --- /dev/null +++ b/app/Policies/EventPolicy.php @@ -0,0 +1,54 @@ +calendar?->team_id !== null + && $user->canAccessTeam($event->calendar->team_id); + } + + /** + * Determine whether the user can update the event. + */ + public function update(User $user, Event $event): bool + { + return $user->id === $event->organizer_id; + } + + /** + * Determine whether the user can remove the event from their calendar. + */ + public function delete(User $user, Event $event): bool + { + return $event->calendar?->team_id !== null + && $user->canAccessTeam($event->calendar->team_id); + } + + /** + * Determine whether the user can answer the event invitation. + */ + public function respond(User $user, Event $event): bool + { + return $event->calendar?->team_id !== null + && $user->canAccessTeam($event->calendar->team_id); + } + + /** + * Determine whether the user can join the event's video room. + */ + public function room(User $user, Event $event): bool + { + return $event->calendar?->team_id !== null + && $user->canAccessTeam($event->calendar->team_id) + && $event->has_video; + } +} diff --git a/app/Services/CalendarService.php b/app/Services/CalendarService.php new file mode 100644 index 0000000..0cc2ddd --- /dev/null +++ b/app/Services/CalendarService.php @@ -0,0 +1,320 @@ +, teamMembers: EloquentCollection} + */ + public function indexData(User $user, ?string $start = null, ?string $end = null): array + { + $teamMembers = User::inTeam($user->team_id) + ->where('id', '!=', $user->id) + ->orderBy('name') + ->get(['id', 'name', 'email']); + + if (! $start) { + $start = now()->startOfMonth()->subDays(14)->toIso8601String(); + } + if (! $end) { + $end = now()->endOfMonth()->addDays(14)->toIso8601String(); + } + + $events = Event::query() + ->select(['id', 'calendar_id', 'organizer_id', 'title', 'start_at', 'end_at', 'has_video']) + ->whereHas('calendar', fn ($query) => $query->where('team_id', $user->team_id)) + ->where(fn ($query) => $query->where('organizer_id', $user->id) + ->orWhereHas('attendees', fn ($attendees) => $attendees + ->where(self::ATTENDEE_TABLE.'.user_id', $user->id) + ->where(self::ATTENDEE_TABLE.'.participation_status', 'accepted'))) + ->whereDoesntHave('attendees', fn ($attendees) => $attendees + ->where(self::ATTENDEE_TABLE.'.user_id', $user->id) + ->whereNotNull(self::ATTENDEE_TABLE.'.hidden_at')) + ->where('start_at', '<=', $end) + ->where('end_at', '>=', $start) + ->orderBy('start_at') + ->get(); + + return [ + 'events' => $events, + 'teamMembers' => $teamMembers, + ]; + } + + /** + * Load a single event with all its detail relations. + */ + public function show(Event $event): Event + { + return $event->load(['organizer:id,name', 'attendees:id,name']); + } + + /** + * Get (or create) the user's personal calendar for their active team. + */ + public function personalCalendar(User $user): Calendar + { + return Calendar::firstOrCreate( + ['team_id' => $user->team_id, 'owner_id' => $user->id], + ['name' => 'My Calendar', 'color' => null], + ); + } + + /** + * Create a new event on the user's calendar. + */ + public function create(array $data, User $user): Event + { + $calendar = $this->personalCalendar($user); + $hasVideo = (bool) ($data['has_video'] ?? false); + + $event = Event::create([ + 'calendar_id' => $calendar->id, + 'organizer_id' => $user->id, + 'title' => $data['title'], + 'description' => $data['description'] ?? null, + 'start_at' => $data['start_at'], + 'end_at' => $data['end_at'], + 'timezone' => $data['timezone'] ?? 'UTC', + 'has_video' => $hasVideo, + 'room_name' => $this->generateRoomName($hasVideo, $data['title']), + ]); + + $event->attendees()->attach( + $this->teamAttendeeIds($user->team_id, $data['attendee_ids'] ?? []) + ->mapWithKeys(fn (int $id) => [$id => ['participation_status' => 'needs_action']]) + ); + + $event->load('attendees'); + $event->attendees->each->notify(new EventInvitation($event)); + + return $event; + } + + /** + * Update an existing event while preserving responses. + */ + public function update(Event $event, array $data): void + { + $hasVideo = (bool) ($data['has_video'] ?? false); + + $event->update([ + 'title' => $data['title'], + 'description' => $data['description'] ?? null, + 'start_at' => $data['start_at'], + 'end_at' => $data['end_at'], + 'timezone' => $data['timezone'] ?? $event->timezone, + 'has_video' => $hasVideo, + 'room_name' => $this->generateRoomName($hasVideo, $data['title'], $event->room_name), + ]); + + $existing = $event->attendees()->pluck(self::ATTENDEE_TABLE.'.participation_status', 'users.id'); + $existingHidden = $event->attendees()->pluck(self::ATTENDEE_TABLE.'.hidden_at', 'users.id'); + + $attendeeIds = $this->teamAttendeeIds($event->calendar->team_id, $data['attendee_ids'] ?? []); + + $event->attendees()->sync( + $attendeeIds->mapWithKeys(fn (int $id) => [ + $id => [ + 'participation_status' => $existing->get($id, 'needs_action'), + 'hidden_at' => $existingHidden->get($id), + ], + ]) + ); + + $addedIds = $attendeeIds->diff($existing->keys()); + + if ($addedIds->isNotEmpty()) { + $this->teamAttendees($event->calendar->team_id, $addedIds) + ->each->notify(new EventInvitation($event)); + } + + $this->deleteInvitationNotifications($event, $existing->keys()->diff($attendeeIds)); + } + + /** + * Remove the event from a user's calendar. + */ + public function hide(Event $event, User $user): void + { + $event->attendees()->syncWithoutDetaching([ + $user->id => ['hidden_at' => now()], + ]); + + if ($this->isAutomaticallyDeletable($event)) { + $this->deletePermanently($event); + } + } + + /** + * Record an attendee's response to an invitation and mark related + * notifications as read. + */ + public function respond(Event $event, User $user, string $response): void + { + $attendee = $event->attendees()->whereKey($user->id)->firstOrFail(); + + $event->attendees()->updateExistingPivot($attendee->id, [ + 'participation_status' => $response, + 'responded_at' => now(), + 'hidden_at' => null, + ]); + + $this->markInvitationNotificationsResponded($user, $event, $response); + + if ($this->isAutomaticallyDeletable($event)) { + $this->deletePermanently($event); + } + } + + /** + * Generate a signed JWT for a Jitsi video room, or null when no secret + * is configured. + */ + public function generateJitsiToken(User $user, string $roomName, bool $isModerator = false): ?string + { + $secret = config('services.jitsi.secret'); + + if (! $secret) { + return null; + } + + return JWT::encode([ + 'aud' => 'jitsi', + 'iss' => config('services.jitsi.app_id'), + 'sub' => config('services.jitsi.app_id'), + 'room' => $roomName, + 'exp' => time() + 3600, + 'context' => [ + 'user' => [ + 'name' => $user->name, + 'email' => $user->email, + 'id' => (string) $user->id, + 'affiliation' => $isModerator ? 'owner' : 'member', + ], + ], + ], $secret, 'HS256'); + } + + // ------------------------------------------------------------------------- + // Private helpers + // ------------------------------------------------------------------------- + + /** + * Generate a unique room name for a video event, reusing an existing one + * when available. + */ + private function generateRoomName(bool $hasVideo, string $title, ?string $existingRoom = null): ?string + { + if (! $hasVideo) { + return null; + } + + return $existingRoom ?? Str::slug($title).'-'.Str::random(10); + } + + /** + * Determine whether the event can be removed from the database: the organizer + * hides it and no pending or visible accepted attendee remains. + */ + private function isAutomaticallyDeletable(Event $event): bool + { + $organizerHidden = $event->attendees() + ->where('users.id', $event->organizer_id) + ->whereNotNull(self::ATTENDEE_TABLE.'.hidden_at') + ->exists(); + + if (! $organizerHidden) { + return false; + } + + $active = $event->attendees() + ->whereIn(self::ATTENDEE_TABLE.'.participation_status', ['accepted', 'needs_action']) + ->whereNull(self::ATTENDEE_TABLE.'.hidden_at') + ->count(); + + return $active === 0; + } + + /** + * Delete the event and its invitations once nobody needs it anymore. + */ + private function deletePermanently(Event $event): void + { + $this->deleteInvitationNotifications($event, $event->attendees->pluck('id')); + + $event->delete(); + } + + /** + * Remove the invitation notifications of an event for the given users. + */ + private function deleteInvitationNotifications(Event $event, Collection $userIds): void + { + if ($userIds->isEmpty()) { + return; + } + + DB::table('notifications') + ->where('type', EventInvitation::class) + ->where('data->event_id', $event->id) + ->whereIn('notifiable_id', $userIds) + ->delete(); + } + + /** + * Mark invitation notifications as responded for a specific user and event. + */ + private function markInvitationNotificationsResponded(User $user, Event $event, string $response): void + { + $user->notifications() + ->where('type', EventInvitation::class) + ->where('data->event_id', $event->id) + ->get() + ->each(function (DatabaseNotification $notification) use ($response) { + $notification->forceFill([ + 'data' => [...$notification->data, 'response' => $response], + 'read_at' => now(), + ])->save(); + }); + } + + /** + * Restrict attendee ids to the members of the event's team. + */ + private function teamAttendeeIds(int $teamId, array $attendeeIds): Collection + { + return User::inTeam($teamId) + ->whereIn('id', $attendeeIds) + ->pluck('id'); + } + + /** + * Fetch the given team members as user models. + */ + private function teamAttendees(int $teamId, Collection $ids): EloquentCollection + { + return User::inTeam($teamId) + ->whereIn('id', $ids) + ->get(); + } +} diff --git a/app/Services/NotificationService.php b/app/Services/NotificationService.php new file mode 100644 index 0000000..2aa7948 --- /dev/null +++ b/app/Services/NotificationService.php @@ -0,0 +1,30 @@ +notifications()->latest()->paginate(self::PER_PAGE); + } + + /** + * Count the notifications a user has not read yet. + */ + public function unreadCountFor(User $user): int + { + return $user->unreadNotifications()->count(); + } +} diff --git a/composer.json b/composer.json index 2ac63eb..e362edc 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "license": "MIT", "require": { "php": "^8.4", + "firebase/php-jwt": "^7.1", "inertiajs/inertia-laravel": "^3.0", "laravel/fortify": "^1.30", "laravel/framework": "^13.0", diff --git a/composer.lock b/composer.lock index 54ed489..9567e2e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a7e8fec39514b3ce056622f14278e794", + "content-hash": "4862ffb94eca7f981210f3a7cf0e75dd", "packages": [ { "name": "bacon/bacon-qr-code", @@ -660,6 +660,72 @@ ], "time": "2025-03-06T22:45:56+00:00" }, + { + "name": "firebase/php-jwt", + "version": "v7.1.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/php-jwt.git", + "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/b374a5d1a4f1f67fadc2165cdb284645945e2fc0", + "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpfastcache/phpfastcache": "^9.2", + "phpseclib/phpseclib": "~3.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present", + "phpseclib/phpseclib": "Support PS256 (RSASSA-PSS) signatures" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/googleapis/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/googleapis/php-jwt/issues", + "source": "https://github.com/googleapis/php-jwt/tree/v7.1.0" + }, + "time": "2026-06-11T17:54:14+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.4.0", diff --git a/config/services.php b/config/services.php index 6a90eb8..6b27717 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,10 @@ ], ], + 'jitsi' => [ + 'domain' => env('JITSI_DOMAIN') ?: 'meet.jit.si', + 'app_id' => env('JITSI_APP_ID'), + 'secret' => env('JITSI_APP_SECRET'), + ], + ]; diff --git a/database/factories/CalendarFactory.php b/database/factories/CalendarFactory.php new file mode 100644 index 0000000..2a88aa7 --- /dev/null +++ b/database/factories/CalendarFactory.php @@ -0,0 +1,30 @@ + + */ +class CalendarFactory extends Factory +{ + protected $model = Calendar::class; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'owner_id' => User::factory(), + 'team_id' => null, + 'name' => fake()->words(2, true), + 'color' => fake()->hexColor(), + ]; + } +} diff --git a/database/factories/DatabaseNotificationFactory.php b/database/factories/DatabaseNotificationFactory.php new file mode 100644 index 0000000..f6c97a4 --- /dev/null +++ b/database/factories/DatabaseNotificationFactory.php @@ -0,0 +1,60 @@ + + */ +class DatabaseNotificationFactory extends Factory +{ + protected $model = DatabaseNotification::class; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'id' => (string) Str::uuid(), + 'type' => EventInvitation::class, + 'data' => [ + 'event_id' => fake()->numberBetween(1, 100), + 'title' => fake()->sentence(3), + 'description' => fake()->paragraph(), + 'start_time' => fake()->dateTime()->format('c'), + 'end_time' => fake()->dateTime()->format('c'), + 'inviter' => fake()->name(), + 'has_video' => false, + 'response' => 'needs_action', + ], + 'read_at' => null, + ]; + } + + /** + * A notification the user already opened. + */ + public function read(): static + { + return $this->state(fn () => ['read_at' => now()]); + } + + /** + * A notification belonging to the given notifiable. + */ + public function forNotifiable(Model $notifiable): static + { + return $this->state(fn () => [ + 'notifiable_id' => $notifiable->getKey(), + 'notifiable_type' => $notifiable->getMorphClass(), + ]); + } +} diff --git a/database/factories/EventFactory.php b/database/factories/EventFactory.php new file mode 100644 index 0000000..fd1640b --- /dev/null +++ b/database/factories/EventFactory.php @@ -0,0 +1,36 @@ + + */ +class EventFactory extends Factory +{ + protected $model = Event::class; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'calendar_id' => Calendar::factory(), + 'organizer_id' => User::factory(), + 'title' => fake()->sentence(3), + 'description' => fake()->optional()->paragraph(), + 'start_at' => fake()->dateTimeBetween('now', '+1 week'), + 'end_at' => fn (array $attributes) => fake()->dateTimeBetween($attributes['start_at'], '+2 week'), + 'timezone' => 'UTC', + 'has_video' => false, + 'status' => 'confirmed', + ]; + } +} diff --git a/database/migrations/2026_08_26_190516_create_calendars_table.php b/database/migrations/2026_08_26_190516_create_calendars_table.php new file mode 100644 index 0000000..11db5df --- /dev/null +++ b/database/migrations/2026_08_26_190516_create_calendars_table.php @@ -0,0 +1,38 @@ +id(); + $table->foreignId('owner_id')->constrained('users')->cascadeOnDelete(); + $table->foreignId('team_id')->nullable()->constrained('teams')->cascadeOnDelete(); + $table->string('name'); + $table->string('color', 7)->nullable(); + $table->timestamps(); + + $table->unique(['team_id', 'owner_id']); + }); + + Schema::create('calendar_members', function (Blueprint $table) { + $table->id(); + $table->foreignId('calendar_id')->constrained()->cascadeOnDelete(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->enum('role', ['owner', 'writer', 'reader'])->default('writer'); + $table->timestamps(); + + $table->unique(['calendar_id', 'user_id']); + }); + } + + public function down(): void + { + Schema::dropIfExists('calendar_members'); + Schema::dropIfExists('calendars'); + } +}; diff --git a/database/migrations/2026_08_27_000000_create_events_table.php b/database/migrations/2026_08_27_000000_create_events_table.php new file mode 100644 index 0000000..1c66c2b --- /dev/null +++ b/database/migrations/2026_08_27_000000_create_events_table.php @@ -0,0 +1,47 @@ +id(); + $table->foreignId('calendar_id')->constrained()->cascadeOnDelete(); + $table->foreignId('organizer_id')->nullable()->constrained('users')->nullOnDelete(); + $table->uuid('uid')->unique(); + $table->string('title'); + $table->text('description')->nullable(); + $table->dateTime('start_at'); + $table->dateTime('end_at'); + $table->string('timezone', 50)->default('UTC'); + $table->boolean('has_video')->default(false); + $table->string('room_name')->unique()->nullable(); + $table->enum('status', ['confirmed', 'cancelled'])->default('confirmed'); + $table->timestamps(); + + $table->index('calendar_id'); + }); + + Schema::create('event_attendees', function (Blueprint $table) { + $table->id(); + $table->foreignId('event_id')->constrained()->cascadeOnDelete(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->enum('participation_status', ['needs_action', 'accepted', 'declined', 'tentative'])->default('needs_action'); + $table->timestamp('responded_at')->nullable(); + $table->timestamp('hidden_at')->nullable(); + $table->timestamps(); + + $table->unique(['event_id', 'user_id']); + }); + } + + public function down(): void + { + Schema::dropIfExists('event_attendees'); + Schema::dropIfExists('events'); + } +}; diff --git a/database/migrations/2026_08_29_170312_create_notifications_table.php b/database/migrations/2026_08_29_170312_create_notifications_table.php new file mode 100644 index 0000000..52e3b00 --- /dev/null +++ b/database/migrations/2026_08_29_170312_create_notifications_table.php @@ -0,0 +1,25 @@ +uuid('id')->primary(); + $table->string('type'); + $table->morphs('notifiable'); + $table->text('data'); + $table->timestamp('read_at')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('notifications'); + } +}; diff --git a/package-lock.json b/package-lock.json index 49b11c6..4ce60ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,10 @@ "packages": { "": { "dependencies": { + "@fullcalendar/vue3": "^7.0.2", "@inertiajs/vite": "^3.0.0", "@inertiajs/vue3": "^3.0.0", - "@lucide/vue": "^1.31.0", + "@lucide/vue": "^1.43.0", "@tiptap/core": "^3.27.1", "@tiptap/extension-link": "^3.27.1", "@tiptap/extension-paragraph": "^3.27.1", @@ -17,8 +18,9 @@ "@vueuse/core": "^14.4.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.4.0", "laravel-vite-plugin": "^3.1.3", - "reka-ui": "^2.6.1", + "reka-ui": "^2.10.4", "tailwind-merge": "^3.2.0", "tailwindcss": "^4.1.1", "tw-animate-css": "^1.2.5", @@ -798,6 +800,41 @@ } } }, + "node_modules/@full-ui/headless-calendar": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@full-ui/headless-calendar/-/headless-calendar-7.0.2.tgz", + "integrity": "sha512-i6UlTNjBVuiBca5Sq6OoLxFqK6eaQ/v1XOLObjRkzXLuSuNn+qs9/dUvlzrbeesn7QbRH7+u7lyvlQyq8WvmGA==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "temporal-polyfill": "^1.0.1" + } + }, + "node_modules/@fullcalendar/core": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-7.0.2.tgz", + "integrity": "sha512-EkhE1wkPttp5kKNmUNLsMwl8nUuQmLdj30SPKagOEWMJUE4AHETAu/F/SbYoRq+nksm2GWPe9cQs1kbQP2H9pA==", + "license": "MIT", + "peerDependencies": { + "@full-ui/headless-calendar": "7.0.2", + "temporal-polyfill": "^1.0.1" + } + }, + "node_modules/@fullcalendar/vue3": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@fullcalendar/vue3/-/vue3-7.0.2.tgz", + "integrity": "sha512-QCCMEA5ydWptaGI4y0i/2G/VsnDIL1Ohj9TMY4KB/bfDGnQE6qi6r8EKs7oAzSyWsTR6V/2U5pLPoN1fGWzCUQ==", + "license": "MIT", + "dependencies": { + "@full-ui/headless-calendar": "7.0.2", + "@fullcalendar/core": "7.0.2", + "preact": "^10.29.0" + }, + "peerDependencies": { + "temporal-polyfill": "^1.0.1", + "vue": "^3.0.11" + } + }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", @@ -865,9 +902,9 @@ } }, "node_modules/@inertiajs/core": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-3.6.1.tgz", - "integrity": "sha512-h6+qqkKfpcoZvxWENy/F5yyiD00PIm8lK+ruQkt6HGk4d3N0LMS9GeUbWVQ4+TDZzIxP/vQLurPktnYvDhYeew==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-3.7.0.tgz", + "integrity": "sha512-JzysXTPsOpKcnR7ohwpgKE+UWBrKwW7z23DydWHSxjfQ02tJAKmNnZJAxnX7zH3zUSTqbtPge6QC8XhvfjNXmw==", "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", @@ -884,12 +921,12 @@ } }, "node_modules/@inertiajs/vite": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@inertiajs/vite/-/vite-3.6.1.tgz", - "integrity": "sha512-Kd6OpBrs8AXkNX5ZQme2jfan531BjfqPu8aDGLPD6+cd1V7Wtsnpr9MhuPCYoasJ7bAEEz997KYjVhzHgZdTRg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@inertiajs/vite/-/vite-3.7.0.tgz", + "integrity": "sha512-eoOqvIEgmsktC/b5NuZjsj3VvCJ7GsbvHFN2IgT/7DXjLVdXGygWeyYHmS57AGSbb6yOyebeBR6cYkk6YyHOmg==", "license": "MIT", "dependencies": { - "@inertiajs/core": "3.6.1", + "@inertiajs/core": "3.7.0", "tinyglobby": "^0.2.15" }, "peerDependencies": { @@ -897,12 +934,12 @@ } }, "node_modules/@inertiajs/vue3": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-3.6.1.tgz", - "integrity": "sha512-7M76W7uw1DqxWR5O+OV7Yg23yITTDcRxuO7KCdQhI58rp9+OTv2BZId7ePSBmqahYOeXUZbTfZfVoS2O6/hijA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-3.7.0.tgz", + "integrity": "sha512-RB3RPz0srHnsfo2CBXWF1Ox/l/ArKUIkVpwXwEZJ+U0xzlGfDTy+fFfocwLFsPoWSYfG+MHssTBMPZx82STkyw==", "license": "MIT", "dependencies": { - "@inertiajs/core": "3.6.1", + "@inertiajs/core": "3.7.0", "es-toolkit": "^1.33.0", "laravel-precognition": "^2.0.0" }, @@ -911,9 +948,9 @@ } }, "node_modules/@internationalized/date": { - "version": "3.12.3", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.3.tgz", - "integrity": "sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q==", + "version": "3.12.4", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.4.tgz", + "integrity": "sha512-M1dEn4c1U1HsSlaVR8upZtSqvXrTkHDfv18H01uCSJyjVLDxnBR38v/fMxecmlwXKR4i9HeZcmgQAPE6A+aGJQ==", "license": "Apache-2.0", "dependencies": { "@swc/helpers": "^0.5.0" @@ -960,9 +997,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -983,9 +1020,9 @@ "license": "MIT" }, "node_modules/@lucide/vue": { - "version": "1.31.0", - "resolved": "https://registry.npmjs.org/@lucide/vue/-/vue-1.31.0.tgz", - "integrity": "sha512-NtjEHhcAa7umPh40wrRmlESJqNGdnpc7LziBKFnW3fmlrW0g2xMCDpdWU7WeEHRSl3xOpxbqiFTLKxoK3CoVCg==", + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@lucide/vue/-/vue-1.43.0.tgz", + "integrity": "sha512-Asq2HozXp4s7JxQVTVVeMo6WINVsJr477uNOafM3Qft1K1aDbbgkVuCP3X37UZXcVB4rEGXaIM//04Ndi2GJfQ==", "license": "ISC", "peerDependencies": { "vue": ">=3.0.1" @@ -1030,9 +1067,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.143.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.143.0.tgz", - "integrity": "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==", + "version": "0.147.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz", + "integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -1045,10 +1082,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.6.tgz", + "integrity": "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.3.tgz", - "integrity": "sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.6.tgz", + "integrity": "sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==", "cpu": [ "arm64" ], @@ -1062,9 +1115,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.3.tgz", - "integrity": "sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.6.tgz", + "integrity": "sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==", "cpu": [ "arm64" ], @@ -1078,9 +1131,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.3.tgz", - "integrity": "sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.6.tgz", + "integrity": "sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==", "cpu": [ "x64" ], @@ -1094,9 +1147,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.3.tgz", - "integrity": "sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.6.tgz", + "integrity": "sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==", "cpu": [ "x64" ], @@ -1110,9 +1163,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.3.tgz", - "integrity": "sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.6.tgz", + "integrity": "sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==", "cpu": [ "arm" ], @@ -1126,9 +1179,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.3.tgz", - "integrity": "sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.6.tgz", + "integrity": "sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==", "cpu": [ "arm64" ], @@ -1142,9 +1195,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.3.tgz", - "integrity": "sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.6.tgz", + "integrity": "sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==", "cpu": [ "arm64" ], @@ -1158,9 +1211,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.3.tgz", - "integrity": "sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.6.tgz", + "integrity": "sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==", "cpu": [ "ppc64" ], @@ -1174,9 +1227,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.3.tgz", - "integrity": "sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.6.tgz", + "integrity": "sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==", "cpu": [ "s390x" ], @@ -1190,9 +1243,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.3.tgz", - "integrity": "sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.6.tgz", + "integrity": "sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==", "cpu": [ "x64" ], @@ -1206,9 +1259,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.3.tgz", - "integrity": "sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.6.tgz", + "integrity": "sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==", "cpu": [ "x64" ], @@ -1222,9 +1275,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.3.tgz", - "integrity": "sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.6.tgz", + "integrity": "sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==", "cpu": [ "arm64" ], @@ -1238,9 +1291,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.3.tgz", - "integrity": "sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.6.tgz", + "integrity": "sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==", "cpu": [ "arm64" ], @@ -1254,9 +1307,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.3.tgz", - "integrity": "sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.6.tgz", + "integrity": "sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==", "cpu": [ "x64" ], @@ -1581,9 +1634,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.17.7", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.7.tgz", - "integrity": "sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==", + "version": "3.17.8", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.8.tgz", + "integrity": "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==", "license": "MIT", "funding": { "type": "github", @@ -1591,12 +1644,12 @@ } }, "node_modules/@tanstack/vue-virtual": { - "version": "3.13.35", - "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.35.tgz", - "integrity": "sha512-lOfSPvgPdlaH6Qy+CyIc3XpycitaSQ9GECndGpTuDiu+uDA1am+90yWXwzDSd/20ZM196ggWJLS+Qb6WjVd/OA==", + "version": "3.13.36", + "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.36.tgz", + "integrity": "sha512-gKpExv4RbB9luVG+SucTXoqPZv/gzu/Yvz6BNO+8kpNxJ2x+I/ulryzl5W9BRciahZGp5Tls3Dp5XP1ztVGbMw==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.17.7" + "@tanstack/virtual-core": "3.17.8" }, "funding": { "type": "github", @@ -1607,9 +1660,9 @@ } }, "node_modules/@tiptap/core": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.29.2.tgz", - "integrity": "sha512-oKUkiPUB7noilVYxI9lNzUD4rX17sHub+PYjMfHMWHG9A3nvIy+FdePIVIIhThKWF7ijhr3eIqHY51Bn+GAFtw==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.30.5.tgz", + "integrity": "sha512-3O7N0FyKIfuLV+xrdWyDM3V5eUY/q2CgLjhhMwOAbM1Pu7VPp9VP+TpEYOdH8aRyB+h1vj5hX5A747D8ZrPfHA==", "license": "MIT", "peer": true, "funding": { @@ -1617,40 +1670,40 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/pm": "3.29.2" + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-blockquote": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.29.2.tgz", - "integrity": "sha512-ca4OzKDh0yaxg2+Z56bC2QnWsNsFp2YMRfVig1PDXyMVFMNJpLcnhxgq/9btn+xYAlYrj8RymOeCTYREOR6Zjg==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.30.5.tgz", + "integrity": "sha512-8pf1ZDrl6XlVPUee/2YlWZPFSF7yqsJEX6WLW41x06MT1dapG3Qudcns0znj6kYsX8JXTJ+Mhegy4z19bvTtRg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-bold": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.29.2.tgz", - "integrity": "sha512-elYbGxJsYnBb4leqrcjdIJuiG380BcOgN+UUzvOv+qEjfGVzHodFOMBl3qnmD6urYHNu5/qQK2S0qSSRXKCLNQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.30.5.tgz", + "integrity": "sha512-MLZS+s/BJiJbv2C2M3G4FQGn43kPwYUUr2TiW3afSn+dRkEZlDxx5CwZYbe1PEt2+VX/SIifn945Oqr3s0axSA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-bubble-menu": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.29.2.tgz", - "integrity": "sha512-kzcWarcpr031rZu+R3Hzut5uxb3Qj/xxMDEYZIQ3uiq1yb5vEMXj8/SIyWautk6Nu8Rr1leV3rGdR4NzhzyFAA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.30.5.tgz", + "integrity": "sha512-redcmBInVwmipjF/WEVcNwCUJgJygUv8leidfRb/jBSAwx7GgnQWPr2HVQDk9zeTt3ykWld2NRdrk94Crjymow==", "license": "MIT", "optional": true, "dependencies": { @@ -1661,80 +1714,80 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-bullet-list": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.29.2.tgz", - "integrity": "sha512-3bWcCUPbCHv0XttlMdnAtXLNYWx2pblByMgxmGsaP9FU0QnslGXty6A6gHCqI33ygRg1vrA6U5Wtpwbi5aKu5g==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.30.5.tgz", + "integrity": "sha512-66OGw4suO0Gr/4QAEiSvVi0eSvEqStvu1moHUSvUlwvEqnuB0ME2w9HuRogPElzWdrYLzbBA47mlCi9Veva0ew==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "3.29.2" + "@tiptap/extension-list": "3.30.5" } }, "node_modules/@tiptap/extension-code": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.29.2.tgz", - "integrity": "sha512-c6W5UGuB7WNLpYocsgRzpO2OOTI4QjaI9jjHRMuty9z+s9DtaYM/HrRLNwVh6MopkHb+i/89Wkv8gCS34fftig==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.30.5.tgz", + "integrity": "sha512-0dCt8eBo4sMtw+LjUu+0GF0JrTlREROdWoy8TM5kFPxJ5ZU2LKDiROXDPwXStaaoFFR/aStLH9xSpdz7cHUiUA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-code-block": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.29.2.tgz", - "integrity": "sha512-w153ct8g6dLiPTdXQ6SOIMxX4SEo5Q50AmjdEEEcJ7ZcYUcde/ScSskLHfOYmyt5ZFAiyEwr121+pux+p3/oAQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.30.5.tgz", + "integrity": "sha512-SvkNoOio2xBy9AtSMyFKMp88MTUvyIXsGCnuz71INV2wHdH4VfRPoQLT6e077LpTCa9w6LHyTKtbZA4HYOp7wg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-document": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.29.2.tgz", - "integrity": "sha512-YUamvefLnsqu6124GavVTI7nqcFlQJ12ROB0oSwG69eSBZYNjg1tIs05LFrBxkwf4Xgqd6YzfJ9+FeG428RvzQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.30.5.tgz", + "integrity": "sha512-4mKoD3bBr5W2AQ2Y/7amOqcVw0eqJbUwRtwvxypeo5Hi0PB9O5Ev8P05c3EUTo10bllqdKYXGeCU5AcgdQsHWQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-dropcursor": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.29.2.tgz", - "integrity": "sha512-KKno7cU9r1HdR48CRrsDu69/1UjZdoslq/UcE+Kx+tdhAv/aljXMkRSNzGMrBNOBDmHRgS1+58zm21WQWdQzwA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.30.5.tgz", + "integrity": "sha512-gJxn9PMUee8zazQBYqbOZiI7zTFXPVJ15AzTnLfUu4eDtPieMwtpgcjhCt4bZlp37drLm+Li76wWLirb7iLxsw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extensions": "3.29.2" + "@tiptap/extensions": "3.30.5" } }, "node_modules/@tiptap/extension-floating-menu": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.29.2.tgz", - "integrity": "sha512-CBTq4Xs5aGWr65uFCIkKBms796OhmirWf/ax//iJ4fl9IfwqjwFuc2vQs9PmuwpKn9ctDHo2sMTtvyeCvIt5LQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.30.5.tgz", + "integrity": "sha512-gTjGPWUpGn8IoW533TciZJZC/81LmBgU7zee+aRMRF3ix3K2z1pJjl6knDvrRQA6Kom+yWFaiueqGNXkrk38XQ==", "license": "MIT", "optional": true, "funding": { @@ -1743,80 +1796,80 @@ }, "peerDependencies": { "@floating-ui/dom": "^1.0.0", - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-gapcursor": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.29.2.tgz", - "integrity": "sha512-8Q39UR4/Tit759IeW9xZIe3NMwN11GsuA3FLheDyyGn7RrW02HD3HhUDlazE54Ki4HoosjFmChPlN4Ik2ubdRQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.30.5.tgz", + "integrity": "sha512-h3m2ZA1XXLAfdHwdtG0MZnf0KWbNyP8xTI3RUlTDR5apmKmYVBaeocOJwTcFFZ92gPKqxYKyhteZqYtHOCZGJA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extensions": "3.29.2" + "@tiptap/extensions": "3.30.5" } }, "node_modules/@tiptap/extension-hard-break": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.29.2.tgz", - "integrity": "sha512-eUW3LN3fq8rXnjEUeI3D2QONYdLsU3yYQm4jxlErs2h4cfwrFjgf19VSUFVmm6LrFbbQ0OnDVPeVLL6iOwDw2w==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.30.5.tgz", + "integrity": "sha512-PcL4Z8l/DlauwZUJg0jf6SXKk6/YOXJtd8yYzqHrmCLRoY4kAa7+TxUhc/lWhuitUiOZ8+nB8V/NNM+WR6mRaw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-heading": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.29.2.tgz", - "integrity": "sha512-6W4aIy70Mh7BNlbG9zZ5FBLhJhU2UUEzgZJ/jwYSCcB30o8McLxJSEjhtoHiX8R78Ah2/JzBGvIe5olZlbeE4A==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.30.5.tgz", + "integrity": "sha512-x7e7+p1bWXvwz6vqONPP1SVB73V0gZP7LIDL/5KMnxWLjahMTabgVPgjV30kz7GsOEgUYtEf7eCyGVGNNWL5Dg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-horizontal-rule": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.29.2.tgz", - "integrity": "sha512-8/ZPzbB9X85Mc9/7xVLZupQKBr2UVcQTGr512xtqMW+XkCQRHCph46tRo828YE13IMWI5fWn/FaNCqXG9cULSw==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.30.5.tgz", + "integrity": "sha512-s5t2xM6wPYRJl2cqYplc7Ze8m8xddk4DP2v0aLFcUuD100D1B5eJbxsiwLK6wBAzNwiuVjd486RnmUpcswaXhQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-italic": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.29.2.tgz", - "integrity": "sha512-iH63V/5wsaMnY4Jz0+meaAGhaec4AiOzOduzl6ZZr5IyGhZ1kthyW84ELt0dyLI3hNceAUhaNWc+I7+vX0aoXA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.30.5.tgz", + "integrity": "sha512-Fu9EuSRlHQNGES7UhY4mQod3yUKnWwxsGlPuDJURfwju/Ug04Jz8iRuERZBPcRgLNkwKDmbDsWUZF72RRIL2Uw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-link": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.29.2.tgz", - "integrity": "sha512-DcVer5SqrexKCEP6Ip1UPxJUMvcRCCItSv0wxoGytanrimBh2smvcg6X0DWnjlsi5H0updhyl+atYCmmQXUIXA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.30.5.tgz", + "integrity": "sha512-zsQ+q83HpCYOMTNzdjb12dggE7sZMp0aqQJhArdavSTl8hLbVY/u3qJN88t25IEwAKVK0pcTJfWWA2QFl8bjAQ==", "license": "MIT", "dependencies": { "linkifyjs": "^4.3.3" @@ -1826,14 +1879,14 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-list": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.29.2.tgz", - "integrity": "sha512-WPZ9BHAPT6QeIm1vdVkuoOWvy9a8/EZeJwV2VhU8LXyTAttvzyj4rsbbHyJWvYWlUSTt/QF2AZ2zhKo7u1w3/A==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.30.5.tgz", + "integrity": "sha512-CHThihH+7TA0TfwtmA+eTXP1MAsA/+p011olJHg8Rilj5xA+L+0IFkjhN16JnZkBgSA4MnfEv15UMNfRaNpuVg==", "license": "MIT", "peer": true, "funding": { @@ -1841,118 +1894,118 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/extension-list-item": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.29.2.tgz", - "integrity": "sha512-s8vBVHHFT0Qpu7CzAZ7S1kYmSiVaDvUNvMNcZUWnxj6VPfiwmx0eXd9FsjePrRCMoM5tFmPnhFTHDxY3D/eZeQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.30.5.tgz", + "integrity": "sha512-N0fKUyQkPQBvVB48imjfIfdexU9VsAX1RydajYP2xAt+QOJ8KHVmXv1EGTp+v7pGdZMLdls1cSZ2f352vW3aWQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "3.29.2" + "@tiptap/extension-list": "3.30.5" } }, "node_modules/@tiptap/extension-list-keymap": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.29.2.tgz", - "integrity": "sha512-R+3k8OLnxdCH7Xy9ieOwUt5m2Je74u8mikothGmsYVO2Zyq48fIbmZ+X6RBPCu7DBOI2FIUhHEFbKQeDWvDNmA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.30.5.tgz", + "integrity": "sha512-3pLR2yo29uhowaGMbD8v71XpgdNmqotBg1NXlyTMVFzxELj+VjjeLLTqSguR/iWDUbHXNzIsfMEgpRnNMO//8w==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "3.29.2" + "@tiptap/extension-list": "3.30.5" } }, "node_modules/@tiptap/extension-ordered-list": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.29.2.tgz", - "integrity": "sha512-ndCunC+UsYOpkOtL7vGnDz21UNa45WUlcO9wMT1fbuYow2QnRhsuMlCWENXI52YPPARWuQ0RDgN7q6TaxPERBg==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.30.5.tgz", + "integrity": "sha512-bUGUnSAgjZhoUWBtr+1wRJHF3NnNvuKQr6sQ8le1tJ2yvLq448ZsSZjZGvTNeLsy3GDKBoMJ0rqLUK34+nM3hg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "3.29.2" + "@tiptap/extension-list": "3.30.5" } }, "node_modules/@tiptap/extension-paragraph": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.29.2.tgz", - "integrity": "sha512-7qJj5YTr11vvjNgjDN1ypOfwTovc0QOCYcit/rskeuVgnmQZOZQzC/BbyKLLG7UGnpRLemU/mEGbW9pAqjAXkQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.30.5.tgz", + "integrity": "sha512-GrNNlAImfQhYRtGE95YNAjcTclUUMPHs9JeE9vMgfcoKcOmZ6GsbWUdN0hA55xqwGaUjnroOVtf77K9z1EbkJQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-placeholder": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.29.2.tgz", - "integrity": "sha512-/BlpPIq2JZk6zLaeYVOXazi6dmd0iRriTymNEnFn1doManN1y5HED9LsMeb/AhNhauL5AgmcHgpvAjbsN9k4SA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.30.5.tgz", + "integrity": "sha512-WgkX4ImAAeV+Qe7ATJ+Gio2MmKWON1CKpCKPHWgCObaoMEaSmdoxXPmI9wXMuM+AJydJepp4n7U/V4TVts14rg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extensions": "3.29.2" + "@tiptap/extensions": "3.30.5" } }, "node_modules/@tiptap/extension-strike": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.29.2.tgz", - "integrity": "sha512-aEvLAbddUQZ+FukCreV3q4G2HfNI+odE7E9U+wbq6XsSWKyo8/pDu1muz+TFKNre4blSMOQ3JQmw5UeHDKy+fg==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.30.5.tgz", + "integrity": "sha512-r8IbWUm4YXNCkmc6h6dzuREQIGbO0x9z9l3GfQPUR3LxFtGssDLngE4dFXHRt/ejLWKEauy6clklf7LawtvYzw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-text": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.29.2.tgz", - "integrity": "sha512-Ubko45JWWHe8glBt2PiGNF8hcbys/JNalFhiR7Y1X4iOOtAxAKJJxh3+eq+//NTlGuBPdWGp7zw8EEUp7anjKA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.30.5.tgz", + "integrity": "sha512-pOgj4mIGFlw4NUdA6PCTFP/MHrYWnOYiZRYeu0I3/Yo3iN4Am/CgYBLl8PWsNh+YPO2hA2DWs7ZMke9D2j5R+g==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extension-underline": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.29.2.tgz", - "integrity": "sha512-K7XwH/xS/5AIREWQ00VTEf/W5U0olp7j6wwit7cdd/8nHv6h6AGr1+iEApHKoLXWQZLfGQKzJlT9W61LAl+fHA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.30.5.tgz", + "integrity": "sha512-u12G/WW2uFRY95BzrSAU9RW002K+7lFpSCL6fb7Puh8yLhek3lddOtAx0P+NI/PyMKtcoVMtBxoi+0mwVM7NPQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2" + "@tiptap/core": "3.30.5" } }, "node_modules/@tiptap/extensions": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.29.2.tgz", - "integrity": "sha512-BCz+FCAChSYtUe4BFj97HEO+nSK+J7GxbJgZG4Hg7DT/gI+hRyeNndU8efiQAx3WGdzsFi3UxRpcF1tTQM7iMQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.30.5.tgz", + "integrity": "sha512-5x3OiCYBvXz0G5OGM8f7ka++1dh9EXdNRZ8IcMcEd+QwW4RPwvmJ2EjheA1eRRyMlcbNU7T+4IRlBXURlTetEA==", "license": "MIT", "peer": true, "funding": { @@ -1960,14 +2013,14 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2" + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5" } }, "node_modules/@tiptap/pm": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.29.2.tgz", - "integrity": "sha512-GCOme7xHaS+DSoaA4CDcAD3l6JyBlvZhvCyfsy2Vp6j8tEoBkZWio7soYVosmlyn7zq8/64VeFZP5s47yfG7fQ==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.30.5.tgz", + "integrity": "sha512-gufkLkW2tA6PZPjivYxDiGzTIIftwqhmYI6lvvKu2S4FbhcysJgMAe/GXVSywzCRVVex9SrvCe6RFYrqnwRitQ==", "license": "MIT", "peer": true, "dependencies": { @@ -1991,35 +2044,35 @@ } }, "node_modules/@tiptap/starter-kit": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.29.2.tgz", - "integrity": "sha512-oTu0tysiqk4zgjEtxRHjAQgxUKaAevZwueOWwSWubHdokqp7SpcbE5n9USJv89HKuTUDm3GjnQH6q8HNn/2DsA==", - "license": "MIT", - "dependencies": { - "@tiptap/core": "^3.29.2", - "@tiptap/extension-blockquote": "^3.29.2", - "@tiptap/extension-bold": "^3.29.2", - "@tiptap/extension-bullet-list": "^3.29.2", - "@tiptap/extension-code": "^3.29.2", - "@tiptap/extension-code-block": "^3.29.2", - "@tiptap/extension-document": "^3.29.2", - "@tiptap/extension-dropcursor": "^3.29.2", - "@tiptap/extension-gapcursor": "^3.29.2", - "@tiptap/extension-hard-break": "^3.29.2", - "@tiptap/extension-heading": "^3.29.2", - "@tiptap/extension-horizontal-rule": "^3.29.2", - "@tiptap/extension-italic": "^3.29.2", - "@tiptap/extension-link": "^3.29.2", - "@tiptap/extension-list": "^3.29.2", - "@tiptap/extension-list-item": "^3.29.2", - "@tiptap/extension-list-keymap": "^3.29.2", - "@tiptap/extension-ordered-list": "^3.29.2", - "@tiptap/extension-paragraph": "^3.29.2", - "@tiptap/extension-strike": "^3.29.2", - "@tiptap/extension-text": "^3.29.2", - "@tiptap/extension-underline": "^3.29.2", - "@tiptap/extensions": "^3.29.2", - "@tiptap/pm": "^3.29.2" + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.30.5.tgz", + "integrity": "sha512-cmDRvukpoqjQjhE96q+l3tCLNZZcJKehxK+00Sp9F4XbKecfM2QpZ2TRHh3vi8qhCeDQNyMoCqfNaqznIjLjIQ==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "3.30.5", + "@tiptap/extension-blockquote": "3.30.5", + "@tiptap/extension-bold": "3.30.5", + "@tiptap/extension-bullet-list": "3.30.5", + "@tiptap/extension-code": "3.30.5", + "@tiptap/extension-code-block": "3.30.5", + "@tiptap/extension-document": "3.30.5", + "@tiptap/extension-dropcursor": "3.30.5", + "@tiptap/extension-gapcursor": "3.30.5", + "@tiptap/extension-hard-break": "3.30.5", + "@tiptap/extension-heading": "3.30.5", + "@tiptap/extension-horizontal-rule": "3.30.5", + "@tiptap/extension-italic": "3.30.5", + "@tiptap/extension-link": "3.30.5", + "@tiptap/extension-list": "3.30.5", + "@tiptap/extension-list-item": "3.30.5", + "@tiptap/extension-list-keymap": "3.30.5", + "@tiptap/extension-ordered-list": "3.30.5", + "@tiptap/extension-paragraph": "3.30.5", + "@tiptap/extension-strike": "3.30.5", + "@tiptap/extension-text": "3.30.5", + "@tiptap/extension-underline": "3.30.5", + "@tiptap/extensions": "3.30.5", + "@tiptap/pm": "3.30.5" }, "funding": { "type": "github", @@ -2027,22 +2080,22 @@ } }, "node_modules/@tiptap/vue-3": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.29.2.tgz", - "integrity": "sha512-rLX+V+HXbsVlk+My8mslvbnbVXZiQZHYtbOiRgxugsqZ9SK1mr1FpgZ/ZNcotJAjecT8FJmPa45ccDnVu66eGA==", + "version": "3.30.5", + "resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.30.5.tgz", + "integrity": "sha512-YRHacQy09nFcokAScICxJ6pWr5daWbsLJuBiMo+DJQlr1XLi6o/zFhh3eR9+DKluL4OY3IZDYBYZfDs7YZtJNg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "optionalDependencies": { - "@tiptap/extension-bubble-menu": "^3.29.2", - "@tiptap/extension-floating-menu": "^3.29.2" + "@tiptap/extension-bubble-menu": "^3.30.5", + "@tiptap/extension-floating-menu": "^3.30.5" }, "peerDependencies": { "@floating-ui/dom": "^1.0.0", - "@tiptap/core": "3.29.2", - "@tiptap/pm": "3.29.2", + "@tiptap/core": "3.30.5", + "@tiptap/pm": "3.30.5", "vue": "^3.0.0" } }, @@ -2078,17 +2131,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", - "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.68.0.tgz", + "integrity": "sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/type-utils": "8.67.0", - "@typescript-eslint/utils": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/type-utils": "8.68.0", + "@typescript-eslint/utils": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2101,7 +2154,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.67.0", + "@typescript-eslint/parser": "^8.68.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -2117,17 +2170,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", - "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.68.0.tgz", + "integrity": "sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "debug": "^4.4.3" }, "engines": { @@ -2143,14 +2196,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", - "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.68.0.tgz", + "integrity": "sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.67.0", - "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/tsconfig-utils": "^8.68.0", + "@typescript-eslint/types": "^8.68.0", "debug": "^4.4.3" }, "engines": { @@ -2165,14 +2218,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", - "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.68.0.tgz", + "integrity": "sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0" + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2183,9 +2236,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", - "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.68.0.tgz", + "integrity": "sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==", "dev": true, "license": "MIT", "engines": { @@ -2200,15 +2253,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", - "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.68.0.tgz", + "integrity": "sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2225,9 +2278,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.68.0.tgz", + "integrity": "sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==", "dev": true, "license": "MIT", "engines": { @@ -2239,16 +2292,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", - "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.68.0.tgz", + "integrity": "sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.67.0", - "@typescript-eslint/tsconfig-utils": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/project-service": "8.68.0", + "@typescript-eslint/tsconfig-utils": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2267,16 +2320,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", - "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.68.0.tgz", + "integrity": "sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0" + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2291,13 +2344,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", - "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.68.0.tgz", + "integrity": "sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/types": "8.68.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2421,39 +2474,39 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.41.tgz", - "integrity": "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.42.tgz", + "integrity": "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.8", - "@vue/shared": "3.5.41", + "@vue/shared": "3.5.42", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.41.tgz", - "integrity": "sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz", + "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.41", - "@vue/shared": "3.5.41" + "@vue/compiler-core": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.41.tgz", - "integrity": "sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.42.tgz", + "integrity": "sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.8", - "@vue/compiler-core": "3.5.41", - "@vue/compiler-dom": "3.5.41", - "@vue/compiler-ssr": "3.5.41", - "@vue/shared": "3.5.41", + "@vue/compiler-core": "3.5.42", + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-ssr": "3.5.42", + "@vue/shared": "3.5.42", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.19", @@ -2461,13 +2514,13 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.41.tgz", - "integrity": "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.42.tgz", + "integrity": "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.41", - "@vue/shared": "3.5.41" + "@vue/compiler-dom": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/devtools-core": { @@ -2534,9 +2587,9 @@ } }, "node_modules/@vue/language-core": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.9.tgz", - "integrity": "sha512-in/68oAa4BCtVY6n/nkuhLIkV8DHYd2UivedJ6cMZ6UYtlq9jaoaSNUBHYCVO44z3nKg7MdE5OBoHKt5SxeBKQ==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.11.tgz", + "integrity": "sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==", "dev": true, "license": "MIT", "dependencies": { @@ -2550,9 +2603,9 @@ } }, "node_modules/@vue/language-core/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -2563,51 +2616,51 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.41.tgz", - "integrity": "sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.42.tgz", + "integrity": "sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.41" + "@vue/shared": "3.5.42" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.41.tgz", - "integrity": "sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.42.tgz", + "integrity": "sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.41", - "@vue/shared": "3.5.41" + "@vue/reactivity": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.41.tgz", - "integrity": "sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.42.tgz", + "integrity": "sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.41", - "@vue/runtime-core": "3.5.41", - "@vue/shared": "3.5.41", + "@vue/reactivity": "3.5.42", + "@vue/runtime-core": "3.5.42", + "@vue/shared": "3.5.42", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.41.tgz", - "integrity": "sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.42.tgz", + "integrity": "sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.41", - "@vue/runtime-dom": "3.5.41", - "@vue/shared": "3.5.41" + "@vue/compiler-ssr": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/shared": "3.5.42" } }, "node_modules/@vue/shared": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.41.tgz", - "integrity": "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.42.tgz", + "integrity": "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -2697,9 +2750,9 @@ "license": "MIT" }, "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", "dev": true, "license": "MIT", "engines": { @@ -2710,16 +2763,13 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -2765,9 +2815,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.11.13", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz", - "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2882,9 +2932,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001809", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", - "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "dev": true, "funding": [ { @@ -2903,35 +2953,18 @@ "license": "CC-BY-4.0" }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -2996,9 +3029,9 @@ "license": "MIT" }, "node_modules/concurrently": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.4.tgz", - "integrity": "sha512-trZql+7l/0+WRAsAnEdctr4+iiOS6ZrViI6H8QWcCF9MFS/LT0dKpe8vluB1to6it+OxSI4VospFTIFMW8DJRw==", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.5.tgz", + "integrity": "sha512-JaP/CoftUrCcAFW/g//RbgEGwlelnEae6cfBLgH6ZdO6s8jPkn6p9SB9u6pdVxYXoiSnFqseOlHfrEfF82TVOg==", "dev": true, "license": "MIT", "dependencies": { @@ -3020,19 +3053,6 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/concurrently/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -3074,6 +3094,16 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/date-fns": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -3100,9 +3130,9 @@ "license": "MIT" }, "node_modules/default-browser": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", - "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", "dev": true, "license": "MIT", "dependencies": { @@ -3158,9 +3188,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.403", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.403.tgz", - "integrity": "sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==", + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", "dev": true, "license": "ISC" }, @@ -3208,14 +3238,15 @@ } }, "node_modules/es-toolkit": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", - "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", "license": "MIT", "workspaces": [ "docs", "benchmarks", - "tests/types" + "tests/types", + "tests/browser-compat" ] }, "node_modules/escalade": { @@ -3245,6 +3276,7 @@ "version": "9.39.5", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "peer": true, @@ -3381,6 +3413,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/eslint/node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3399,6 +3447,23 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", @@ -3425,6 +3490,19 @@ "node": "*" } }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", @@ -3560,9 +3638,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", "dev": true, "license": "ISC", "dependencies": { @@ -3889,9 +3967,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -3993,9 +4071,9 @@ } }, "node_modules/laravel-vite-plugin": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-3.1.3.tgz", - "integrity": "sha512-cI5Anw4QHY+UzvZczFaj+j8NhwT2FtyEN8aqS/hOdt6DpEFBsn6x3GENxALem3cc+TsGvd9MacneimEvShvKMA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-3.2.0.tgz", + "integrity": "sha512-xSxY9Gzeb/eancd8WeK09piAFP+a6i5QIBqNCKNv9L0Eq6wziwzSem7F1GvMSrtjMh5F/QVKFxn8t9naGOA66A==", "license": "MIT", "dependencies": { "picocolors": "^1.0.0", @@ -4471,9 +4549,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.53", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", - "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "dev": true, "license": "MIT", "engines": { @@ -4508,15 +4586,15 @@ } }, "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz", + "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", "license": "MIT" }, "node_modules/open": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", - "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.1.tgz", + "integrity": "sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==", "dev": true, "license": "MIT", "dependencies": { @@ -4524,8 +4602,8 @@ "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", - "powershell-utils": "^0.1.0", - "wsl-utils": "^0.3.0" + "powershell-utils": "^0.2.0", + "wsl-utils": "^1.0.0" }, "engines": { "node": ">=20" @@ -4705,9 +4783,9 @@ } }, "node_modules/powershell-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", - "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.0.tgz", + "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", "dev": true, "license": "MIT", "engines": { @@ -4717,6 +4795,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/preact": { + "version": "10.29.8", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz", + "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4842,9 +4938,9 @@ } }, "node_modules/prosemirror-changeset": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", - "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.2.tgz", + "integrity": "sha512-ViYrjMSg3YFiXwIhKaluu+/mi3Yrxt6AR8ri14ulTaGcZtXO1CThl7A2gv79qx5fQnOw8woKwyBU2u+9PVCm3w==", "license": "MIT", "dependencies": { "prosemirror-transform": "^1.0.0" @@ -4970,9 +5066,9 @@ } }, "node_modules/prosemirror-view": { - "version": "1.42.2", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.2.tgz", - "integrity": "sha512-Pdg0l5kXm8aLDquFAnQFTCITg0q44sLqBlHlpsVLD9segdOao8TOfQdAhCrCXyVgPSRr6UDDROOIWA3bIrN9YQ==", + "version": "1.42.3", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.42.3.tgz", + "integrity": "sha512-oTN7EtH+CpwxU9NrwEYWd0UZ4JUx7l048l5A2Xppm4p/60isZYLnth9QVQmC3VRIvdrIWCxwZSd+Uz791G31/w==", "license": "MIT", "dependencies": { "prosemirror-model": "^1.25.8", @@ -5012,9 +5108,9 @@ "license": "MIT" }, "node_modules/reka-ui": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.10.3.tgz", - "integrity": "sha512-nJGZbwcha8AcP2wbnjodfzsciTKBqp1mIzepC9Pi2xDI/YK3++ej3vpJOSPyxqrkq1Oorj4K+BdJkbVCV6x6ag==", + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.10.4.tgz", + "integrity": "sha512-kbS5GAbkHkYj0EVKAg5ZPEPndhBjeUFSa1Aq5m5ftQwyHnB1v5tw8X6fcwfKH/ry3StPXblMWM1DW82MVS71cw==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.13", @@ -5058,12 +5154,12 @@ } }, "node_modules/rolldown": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.3.tgz", - "integrity": "sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz", + "integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==", "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.143.0", + "@oxc-project/types": "=0.147.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -5073,20 +5169,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.3", - "@rolldown/binding-darwin-arm64": "1.2.3", - "@rolldown/binding-darwin-x64": "1.2.3", - "@rolldown/binding-freebsd-x64": "1.2.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.3", - "@rolldown/binding-linux-arm64-gnu": "1.2.3", - "@rolldown/binding-linux-arm64-musl": "1.2.3", - "@rolldown/binding-linux-ppc64-gnu": "1.2.3", - "@rolldown/binding-linux-s390x-gnu": "1.2.3", - "@rolldown/binding-linux-x64-gnu": "1.2.3", - "@rolldown/binding-linux-x64-musl": "1.2.3", - "@rolldown/binding-openharmony-arm64": "1.2.3", - "@rolldown/binding-win32-arm64-msvc": "1.2.3", - "@rolldown/binding-win32-x64-msvc": "1.2.3" + "@rolldown/binding-android-arm-eabi": "1.2.6", + "@rolldown/binding-android-arm64": "1.2.6", + "@rolldown/binding-darwin-arm64": "1.2.6", + "@rolldown/binding-darwin-x64": "1.2.6", + "@rolldown/binding-freebsd-x64": "1.2.6", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.6", + "@rolldown/binding-linux-arm64-gnu": "1.2.6", + "@rolldown/binding-linux-arm64-musl": "1.2.6", + "@rolldown/binding-linux-ppc64-gnu": "1.2.6", + "@rolldown/binding-linux-s390x-gnu": "1.2.6", + "@rolldown/binding-linux-x64-gnu": "1.2.6", + "@rolldown/binding-linux-x64-musl": "1.2.6", + "@rolldown/binding-openharmony-arm64": "1.2.6", + "@rolldown/binding-win32-arm64-msvc": "1.2.6", + "@rolldown/binding-win32-x64-msvc": "1.2.6" } }, "node_modules/rope-sequence": { @@ -5311,6 +5408,29 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/temporal-polyfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-1.0.4.tgz", + "integrity": "sha512-MLEU0qOD2uXlz24oINNtdLZQl8RgmMxSnRtKEGZGGetTJjlRwQJjk+VsJ4EREaUoiaTb8NJOcUiKtoAiWn9EBg==", + "license": "MIT", + "peer": true, + "dependencies": { + "temporal-spec": "1.0.1", + "temporal-utils": "1.0.2" + } + }, + "node_modules/temporal-spec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-1.0.1.tgz", + "integrity": "sha512-wxVoanmDeavXie1vu2JaQ3WIc3JZnWAOYFBsJyATaVsXsycKYUflGsyBmrRSnoCpZJpwPyr38VpgSUlQ8CbFxg==", + "license": "Apache-2.0" + }, + "node_modules/temporal-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/temporal-utils/-/temporal-utils-1.0.2.tgz", + "integrity": "sha512-1B8Dl4KzrOvsNUlpoWGno2VLQlxroLjDgc5NBjVC9ax9ymdo+ezfyvhyjEMx+IVfhINr6CIG2gcnlP95iRrybQ==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -5345,9 +5465,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "peer": true, "engines": { @@ -5447,16 +5567,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", - "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.68.0.tgz", + "integrity": "sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.67.0", - "@typescript-eslint/parser": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0" + "@typescript-eslint/eslint-plugin": "8.68.0", + "@typescript-eslint/parser": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5495,9 +5615,9 @@ } }, "node_modules/unplugin-utils/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -5508,9 +5628,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", - "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "dev": true, "funding": [ { @@ -5556,16 +5676,16 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", - "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "license": "MIT", "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", - "postcss": "^8.5.25", - "rolldown": "~1.2.1", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", "tinyglobby": "^0.2.17" }, "bin": { @@ -5582,7 +5702,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -5651,9 +5771,9 @@ } }, "node_modules/vite-dev-rpc/node_modules/birpc": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.1.0.tgz", - "integrity": "sha512-O8L9vALWGqdEe0cG4HJckauw3WeJETlJnDRPUYpgwB7wrU43b/5NGMdVjdVcRo+4ROgd3ih2wha1glDe4HRVgw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.2.0.tgz", + "integrity": "sha512-KxgKcZPfrtzJDDALHPguGpGJUrzdgpymyiQQgzFjWreHMOpWrnFNVREr5J48x2DBh8ZVioscrV1SBkDipGiX+Q==", "dev": true, "license": "MIT", "funding": { @@ -5967,9 +6087,9 @@ } }, "node_modules/vite/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "engines": { "node": ">=12" @@ -5979,24 +6099,24 @@ } }, "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.2.0.tgz", + "integrity": "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==", "dev": true, "license": "MIT" }, "node_modules/vue": { - "version": "3.5.41", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.41.tgz", - "integrity": "sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg==", + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.42.tgz", + "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==", "license": "MIT", "peer": true, "dependencies": { - "@vue/compiler-dom": "3.5.41", - "@vue/compiler-sfc": "3.5.41", - "@vue/runtime-dom": "3.5.41", - "@vue/server-renderer": "3.5.41", - "@vue/shared": "3.5.41" + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-sfc": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/server-renderer": "3.5.42", + "@vue/shared": "3.5.42" }, "peerDependencies": { "typescript": "*" @@ -6116,15 +6236,15 @@ } }, "node_modules/vue-tsc": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.9.tgz", - "integrity": "sha512-TS3Y1ux/IRoE8OCP2PpACAeOseuIs0UvWrcr7u+w3PmfY+SlCfEf8zjrBgnQksHUgLpthi5vHlffcQTQTdPBZA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.11.tgz", + "integrity": "sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "@volar/typescript": "2.4.28", - "@vue/language-core": "3.3.9" + "@vue/language-core": "3.3.11" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -6195,29 +6315,29 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/wsl-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", "dev": true, "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, "engines": { - "node": ">=12" + "node": ">=20" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wsl-utils": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", - "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", "dev": true, "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0", - "powershell-utils": "^0.1.0" - }, "engines": { "node": ">=20" }, diff --git a/package.json b/package.json index 720856c..5fc7afd 100644 --- a/package.json +++ b/package.json @@ -31,9 +31,10 @@ "vue-tsc": "^3.3.9" }, "dependencies": { + "@fullcalendar/vue3": "^7.0.2", "@inertiajs/vite": "^3.0.0", "@inertiajs/vue3": "^3.0.0", - "@lucide/vue": "^1.31.0", + "@lucide/vue": "^1.43.0", "@tiptap/core": "^3.27.1", "@tiptap/extension-link": "^3.27.1", "@tiptap/extension-paragraph": "^3.27.1", @@ -43,8 +44,9 @@ "@vueuse/core": "^14.4.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.4.0", "laravel-vite-plugin": "^3.1.3", - "reka-ui": "^2.6.1", + "reka-ui": "^2.10.4", "tailwind-merge": "^3.2.0", "tailwindcss": "^4.1.1", "tw-animate-css": "^1.2.5", diff --git a/resources/js/app.ts b/resources/js/app.ts index d40556f..09694c2 100644 --- a/resources/js/app.ts +++ b/resources/js/app.ts @@ -1,7 +1,11 @@ import { createInertiaApp } from '@inertiajs/vue3'; import { initializeTheme } from './composables/useAppearance'; -const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; +import '@fullcalendar/vue3/skeleton.css'; +import '@fullcalendar/vue3/themes/forma/palettes/purple.css'; +import '@fullcalendar/vue3/themes/forma/theme.css'; + +const appName = import.meta.env.VITE_APP_NAME || 'Taskly'; createInertiaApp({ title: (title) => (title ? `${title} - ${appName}` : appName), diff --git a/resources/js/components/AppSidebar.vue b/resources/js/components/AppSidebar.vue index 583a140..03ea9a1 100644 --- a/resources/js/components/AppSidebar.vue +++ b/resources/js/components/AppSidebar.vue @@ -16,7 +16,7 @@ import { dashboard } from '@/routes'; import { index } from '@/routes/tasks'; import { type NavItem } from '@/types'; import { Link } from '@inertiajs/vue3'; -import { Folder, LayoutGrid, ListCheck, Tag } from '@lucide/vue'; +import { Folder, LayoutGrid, ListCheck, Calendar } from '@lucide/vue'; import AppLogo from './AppLogo.vue'; const mainNavItems: NavItem[] = [ @@ -31,9 +31,9 @@ const mainNavItems: NavItem[] = [ icon: ListCheck, }, { - title: 'Tags', - href: '/tags', - icon: Tag, + title: 'Calendar', + href: '/calendar', + icon: Calendar, }, ]; diff --git a/resources/js/components/AppSidebarHeader.vue b/resources/js/components/AppSidebarHeader.vue index 3fd430c..4729b8d 100644 --- a/resources/js/components/AppSidebarHeader.vue +++ b/resources/js/components/AppSidebarHeader.vue @@ -1,5 +1,6 @@ + + diff --git a/resources/js/components/calendar/CalendarPageSkeleton.vue b/resources/js/components/calendar/CalendarPageSkeleton.vue new file mode 100644 index 0000000..37b94df --- /dev/null +++ b/resources/js/components/calendar/CalendarPageSkeleton.vue @@ -0,0 +1,37 @@ + + + diff --git a/resources/js/components/calendar/DateTimeField.vue b/resources/js/components/calendar/DateTimeField.vue new file mode 100644 index 0000000..e8505fd --- /dev/null +++ b/resources/js/components/calendar/DateTimeField.vue @@ -0,0 +1,87 @@ + + + diff --git a/resources/js/components/calendar/EventDialog.vue b/resources/js/components/calendar/EventDialog.vue new file mode 100644 index 0000000..3db4450 --- /dev/null +++ b/resources/js/components/calendar/EventDialog.vue @@ -0,0 +1,397 @@ + + +