diff --git a/frontend/src/components/LoginModal.tsx b/frontend/src/components/LoginModal.tsx
index 4974729..9c9cce3 100644
--- a/frontend/src/components/LoginModal.tsx
+++ b/frontend/src/components/LoginModal.tsx
@@ -1,5 +1,7 @@
import React, { useState, useEffect } from 'react';
import { X, Mail, Lock, ArrowRight, Loader2 } from 'lucide-react';
+import { Capacitor } from '@capacitor/core';
+import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
interface LoginModalProps {
isOpen: boolean;
@@ -101,8 +103,70 @@ export const LoginModal: React.FC = ({ isOpen, onClose, onSwitc
}
};
+ const handleNativeGoogleLogin = async () => {
+ setError('');
+ setIsLoading(true);
+ try {
+ const user = await GoogleAuth.signIn();
+ console.log('[Native OAuth] Google user received:', user);
+
+ const idToken = user.authentication.idToken;
+ if (!idToken) {
+ throw new Error('Không nhận được token từ Google.');
+ }
+
+ const response = await fetch(`/api/v1/auth/google`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ credential: idToken }),
+ });
+
+ const data = await response.json();
+ if (!response.ok) {
+ throw new Error(data.message || 'Đăng nhập Google thất bại');
+ }
+
+ localStorage.setItem('token', data.access_token);
+ localStorage.setItem('user', JSON.stringify(data.user));
+ localStorage.removeItem('guest_token');
+ localStorage.removeItem('guest_user');
+ console.log('[Native OAuth] Google login successful');
+
+ let pendingInviteToken = localStorage.getItem('pendingInviteToken');
+ if (pendingInviteToken) {
+ try {
+ const joinRes = await fetch(`/api/v1/tours/join-by-token`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${data.access_token}`,
+ },
+ body: JSON.stringify({ token: pendingInviteToken }),
+ });
+ if (joinRes.ok) {
+ localStorage.removeItem('pendingInviteToken');
+ }
+ } catch (joinErr) {
+ console.error('[Native OAuth] Join tour after login failed:', joinErr);
+ }
+ }
+
+ if (onLoginSuccess) {
+ onLoginSuccess(data.user);
+ }
+ onClose();
+ } catch (err: any) {
+ console.error('[Native OAuth] Error:', err);
+ if (err?.message !== 'Sign in window was closed' && err?.message !== '12501') {
+ setError(err.message || 'Đăng nhập Google thất bại');
+ }
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
useEffect(() => {
- if (!isOpen) return;
+ if (!isOpen || Capacitor.isNativePlatform()) return;
const timer = setTimeout(() => {
if (typeof window !== 'undefined' && (window as any).google) {
@@ -244,7 +308,23 @@ export const LoginModal: React.FC = ({ isOpen, onClose, onSwitc
Hoặc
diff --git a/frontend/src/components/PhotoTaker.tsx b/frontend/src/components/PhotoTaker.tsx
new file mode 100644
index 0000000..fa8049c
--- /dev/null
+++ b/frontend/src/components/PhotoTaker.tsx
@@ -0,0 +1,73 @@
+import React, { useState } from 'react';
+import { Camera as CameraIcon, X } from 'lucide-react';
+import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
+import { useNotification } from '@/hooks/useNotification';
+
+interface PhotoTakerProps {
+ onPhotoTaken?: (webPath: string) => void;
+ onClose?: () => void;
+}
+
+export const PhotoTaker: React.FC = ({ onPhotoTaken, onClose }) => {
+ const [photoUri, setPhotoUri] = useState();
+ const notify = useNotification();
+
+ const takeAndSavePhoto = async () => {
+ try {
+ const image = await Camera.getPhoto({
+ quality: 90,
+ allowEditing: false, // Giữ nguyên ảnh gốc, không qua chỉnh sửa
+ resultType: CameraResultType.Uri,
+ source: CameraSource.Camera, // Mở camera trực tiếp
+ saveToGallery: true, // Tự động lưu ảnh gốc vào thư viện điện thoại
+ });
+
+ setPhotoUri(image.webPath);
+ notify({
+ title: 'Thành công',
+ message: 'Ảnh đã được chụp và tự động lưu vào thư viện điện thoại.',
+ type: 'success'
+ });
+ if (onPhotoTaken && image.webPath) {
+ onPhotoTaken(image.webPath);
+ }
+ } catch (error: any) {
+ console.error('Lỗi khi chụp hoặc lưu ảnh:', error);
+ if (error?.message !== 'User cancelled photos app') {
+ notify({
+ title: 'Lỗi chụp ảnh',
+ message: 'Không thể truy cập camera hoặc lưu ảnh.',
+ type: 'error'
+ });
+ }
+ }
+ };
+
+ return (
+
+
+
Chụp ảnh hành trình
+ {onClose && (
+
+
+
+ )}
+
+
+
+
+ Chụp và Lưu Ảnh Gốc
+
+
+ {photoUri && (
+
+
Xem trước ảnh vừa chụp:
+
+
+ )}
+
+ );
+};
diff --git a/frontend/src/components/PublicPhotoModal.tsx b/frontend/src/components/PublicPhotoModal.tsx
index 130e158..da0ffa3 100644
--- a/frontend/src/components/PublicPhotoModal.tsx
+++ b/frontend/src/components/PublicPhotoModal.tsx
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef } from 'react';
import { X, Send, MessageSquare, User, Loader2, Calendar, MapPin, Download, Edit, Heart, Trash2 } from 'lucide-react';
import { io } from 'socket.io-client';
+import { Capacitor } from '@capacitor/core';
import { CoordinateSelectModal } from './CoordinateSelectModal';
import { useTranslation } from '../hooks/useTranslation';
import { useConfirm } from '../hooks/useConfirm';
@@ -246,7 +247,9 @@ export const PublicPhotoModal: React.FC = ({
fetchComments();
- const socket = io();
+ const socket = Capacitor.isNativePlatform()
+ ? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
+ : io();
socket.emit('joinPhoto', photo.id);
socket.on('photoCommentAdded', (newCommentData: any) => {
diff --git a/frontend/src/components/TourChat.tsx b/frontend/src/components/TourChat.tsx
index 2a3e8c2..d69b0db 100644
--- a/frontend/src/components/TourChat.tsx
+++ b/frontend/src/components/TourChat.tsx
@@ -1,5 +1,7 @@
import React, { useState, useEffect, useRef } from 'react';
import { io, Socket } from 'socket.io-client';
+import { Capacitor } from '@capacitor/core';
+import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Send, MessageSquare, Loader2, Image as ImageIcon, MapPin, Download, X } from 'lucide-react';
import { useNotification } from '@/hooks/useNotification';
@@ -87,7 +89,7 @@ export const TourChat: React.FC = ({ tourId, embedded = false })
}, []);
const filteredParticipants = participants.filter(p =>
- p.name.toLowerCase().includes(mentionSearch.toLowerCase())
+ p && p.name && p.name.toLowerCase().includes(mentionSearch.toLowerCase())
);
const handleInputChange = (e: React.ChangeEvent) => {
@@ -179,7 +181,9 @@ export const TourChat: React.FC = ({ tourId, embedded = false })
// Connect to socket and listen for tour messages
useEffect(() => {
- const socket = io();
+ const socket = Capacitor.isNativePlatform()
+ ? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
+ : io();
socketRef.current = socket;
socket.on('connect', () => {
@@ -252,6 +256,41 @@ export const TourChat: React.FC = ({ tourId, embedded = false })
});
};
+ // Handle Native Image Selection (Camera or Library)
+ const handleNativePhotoSelect = async () => {
+ try {
+ const image = await Camera.getPhoto({
+ quality: 90,
+ allowEditing: false,
+ resultType: CameraResultType.Uri,
+ source: CameraSource.Prompt, // Prompt selection
+ saveToGallery: true, // Auto-save original photo to device gallery
+ promptLabelHeader: 'Chọn hình ảnh',
+ promptLabelPhoto: 'Chọn từ thư viện',
+ promptLabelPicture: 'Chụp ảnh mới (Camera)'
+ });
+
+ if (image && image.webPath) {
+ setImagePreview(image.webPath);
+
+ // Convert Capacitor webPath resource back to standard File instance
+ const response = await fetch(image.webPath);
+ const blob = await response.blob();
+ const file = new File([blob], `photo.${image.format}`, { type: `image/${image.format}` });
+ setSelectedImage(file);
+ }
+ } catch (error: any) {
+ console.error('Lỗi chọn ảnh native:', error);
+ if (error?.message !== 'User cancelled photos app' && error?.message !== 'User cancelled camera') {
+ notify({
+ title: 'Lỗi',
+ message: 'Không thể truy cập máy ảnh hoặc thư viện ảnh.',
+ type: 'error'
+ });
+ }
+ }
+ };
+
// Handle Image Selection
const handleImageChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
@@ -613,7 +652,7 @@ export const TourChat: React.FC = ({ tourId, embedded = false })
{/* Attach photo button */}
fileInputRef.current?.click()}
+ onClick={Capacitor.isNativePlatform() ? handleNativePhotoSelect : () => fileInputRef.current?.click()}
className="p-2.5 bg-white border border-gray-200 hover:bg-gray-50 text-gray-500 rounded-xl transition-all shadow-sm active:scale-95 flex items-center justify-center shrink-0"
title="Đính kèm hình ảnh"
>
diff --git a/frontend/src/hooks/useNotification.tsx b/frontend/src/hooks/useNotification.tsx
index 46a7a09..a924610 100644
--- a/frontend/src/hooks/useNotification.tsx
+++ b/frontend/src/hooks/useNotification.tsx
@@ -1,5 +1,7 @@
import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
import { NotificationModal } from '../components/NotificationModal';
+import { Capacitor } from '@capacitor/core';
+import { LocalNotifications } from '@capacitor/local-notifications';
interface NotificationOptions {
title: string;
@@ -24,6 +26,24 @@ export const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({
message,
type,
});
+
+ if (Capacitor.isNativePlatform()) {
+ LocalNotifications.schedule({
+ notifications: [
+ {
+ title: title || 'YoTrip',
+ body: message,
+ id: Math.floor(Math.random() * 1000000),
+ schedule: { at: new Date(Date.now() + 100) },
+ sound: 'default',
+ actionTypeId: 'OPEN_APP',
+ extra: null
+ }
+ ]
+ }).catch(err => {
+ console.error('[LocalNotifications] Error scheduling native notification:', err);
+ });
+ }
}, []);
const handleClose = useCallback(() => {
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 7d506ed..4334fba 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
+import './utils/nativePatch';
import App from './App.js';
ReactDOM.createRoot(document.getElementById('root')!).render(
diff --git a/frontend/src/pages/MemberDashboard.tsx b/frontend/src/pages/MemberDashboard.tsx
index d24ec29..87c7f31 100644
--- a/frontend/src/pages/MemberDashboard.tsx
+++ b/frontend/src/pages/MemberDashboard.tsx
@@ -1,17 +1,18 @@
import React, { useEffect, useState, useRef } from 'react';
-
-import {
- Compass,
- Users,
- Image as ImageIcon,
- MessageSquare,
- LogOut,
- Search,
- Check,
- X,
- Trash2,
- Send,
- UserPlus,
+import { io, Socket } from 'socket.io-client';
+import { Capacitor } from '@capacitor/core';
+import {
+ Compass,
+ Users,
+ Image as ImageIcon,
+ MessageSquare,
+ LogOut,
+ Search,
+ Check,
+ X,
+ Trash2,
+ Send,
+ UserPlus,
Clock,
ChevronRight,
ChevronLeft,
@@ -110,7 +111,7 @@ export const MemberDashboard: React.FC = ({
const [attachedLocation, setAttachedLocation] = useState<{ latitude: number; longitude: number } | null>(null);
const [isUploading, setIsUploading] = useState(false);
const [isLocating, setIsLocating] = useState(false);
-
+
// Emergency share states
const [sharingTour, setSharingTour] = useState(null);
const [shareStatus, setShareStatus] = useState(null);
@@ -187,7 +188,7 @@ export const MemberDashboard: React.FC = ({
// Send location message to tour chat
const token = localStorage.getItem('token');
const message = `📍 Vị trí hiện tại: ${position.latitude.toFixed(6)}, ${position.longitude.toFixed(6)}\n🔗 Google Maps: https://maps.google.com/?q=${position.latitude},${position.longitude}`;
-
+
const res = await fetch(`/api/v1/tours/${tour.id}/messages`, {
method: 'POST',
headers: {
@@ -320,7 +321,7 @@ export const MemberDashboard: React.FC = ({
}
}
};
-
+
const fileInputRef = useRef(null);
const cameraInputRef = useRef(null);
@@ -344,10 +345,10 @@ export const MemberDashboard: React.FC = ({
const isMemberOfMyTours = (senderId: string) => {
if (!publicTours) return false;
- const userTours = publicTours.filter(tour =>
+ const userTours = publicTours.filter(tour =>
tour.participants?.some((p: any) => p.userId === user?.id)
);
- return userTours.some(tour =>
+ return userTours.some(tour =>
tour.participants?.some((p: any) => p.userId === senderId && p.userId !== user?.id)
);
};
@@ -527,8 +528,18 @@ export const MemberDashboard: React.FC = ({
useEffect(() => {
if (!user?.id) return;
- const handleMessageReceived = (e: Event) => {
- const message = (e as CustomEvent).detail;
+ // Connect to WebSocket using same origin/proxy
+ const socket = Capacitor.isNativePlatform()
+ ? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
+ : io();
+ socketRef.current = socket;
+
+ socket.on('connect', () => {
+ console.log('[WS] MemberDashboard connected:', socket.id);
+ socket.emit('joinUser', user.id);
+ });
+
+ socket.on('messageReceived', (message: any) => {
// If we are actively chatting with the sender of this message
if (activeChatUser && (message.senderId === activeChatUser.id || message.receiverId === activeChatUser.id)) {
setChatMessages(prev => [...prev, message]);
@@ -806,7 +817,7 @@ export const MemberDashboard: React.FC = ({
// Filter tours where the current logged-in user is a participant
const myTours = React.useMemo(() => {
if (!publicTours) return [];
- return publicTours.filter(tour =>
+ return publicTours.filter(tour =>
tour.participants?.some((p: any) => p.userId === user?.id)
);
}, [publicTours, user?.id]);
@@ -819,7 +830,7 @@ export const MemberDashboard: React.FC = ({
}
const isPendingReceived = receivedRequests.find(r => r.requester?.id === targetId);
if (isPendingReceived) return 'Chờ bạn duyệt';
-
+
const isPendingSent = sentRequests.find(s => s.receiver?.id === targetId);
if (isPendingSent) return 'Đã gửi yêu cầu';
@@ -827,7 +838,7 @@ export const MemberDashboard: React.FC = ({
};
// Helper function to render a user's initials avatar
-const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') => {
+ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') => {
const initials = name
? name.split(' ').map(n => n[0]).slice(0, 2).join('').toUpperCase()
: 'U';
@@ -856,9 +867,9 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
{user?.avatar ? (
-
) : (
@@ -876,11 +887,10 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
type: 'info'
});
}}
- className={`absolute -bottom-1 -right-1 p-1.5 rounded-full border shadow-md transition-all active:scale-95 z-20 ${
- muteNotifications
- ? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
+ className={`absolute -bottom-1 -right-1 p-1.5 rounded-full border shadow-md transition-all active:scale-95 z-20 ${muteNotifications
+ ? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
: 'bg-indigo-650 border-indigo-500 text-white hover:bg-indigo-600'
- }`}
+ }`}
title={muteNotifications ? "Bật thông báo đẩy" : "Tắt thông báo đẩy"}
>
{muteNotifications ? (
@@ -931,7 +941,7 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
{/* Explore Map Quick Button */}
-
@@ -944,11 +954,10 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
handleSelectTab('tours')}
- className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${
- activeTab === 'tours'
- ? 'bg-indigo-900/40 border-indigo-500/40'
+ className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'tours'
+ ? 'bg-indigo-900/40 border-indigo-500/40'
: 'bg-slate-850/80 border-slate-700/80'
- }`}
+ }`}
>
@@ -972,11 +981,10 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
handleSelectTab('photos')}
- className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${
- activeTab === 'photos'
- ? 'bg-indigo-900/40 border-indigo-500/40'
+ className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'photos'
+ ? 'bg-indigo-900/40 border-indigo-500/40'
: 'bg-slate-850/80 border-slate-700/80'
- }`}
+ }`}
>
@@ -998,11 +1006,10 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
handleSelectTab('connections')}
- className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${
- activeTab === 'connections'
- ? 'bg-indigo-900/40 border-indigo-500/40'
+ className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'connections'
+ ? 'bg-indigo-900/40 border-indigo-500/40'
: 'bg-slate-900/60 border-slate-800/60'
- }`}
+ }`}
>
@@ -1026,11 +1033,10 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
handleSelectTab('chats')}
- className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${
- activeTab === 'chats'
- ? 'bg-indigo-900/40 border-indigo-500/40'
+ className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'chats'
+ ? 'bg-indigo-900/40 border-indigo-500/40'
: 'bg-slate-900/60 border-slate-800/60'
- }`}
+ }`}
>
@@ -1069,23 +1075,22 @@ const renderInitialsAvatar = (name: string, sizeClass = 'w-10 h-10 text-sm') =>
);
}
-return (
+ return (
-
+
{/* Background Glow */}
-
-
+ }`}>
+
{/* Mobile Detail Header: Only on Mobile detail mode */}
{showMobileHeader && (
-
@@ -1108,9 +1113,9 @@ return (
{user?.avatar ? (
-
) : (
@@ -1133,11 +1138,10 @@ return (
type: 'info'
});
}}
- className={`absolute -bottom-1 -right-1 p-1.5 rounded-full border shadow-md transition-all active:scale-90 z-20 ${
- muteNotifications
- ? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
+ className={`absolute -bottom-1 -right-1 p-1.5 rounded-full border shadow-md transition-all active:scale-90 z-20 ${muteNotifications
+ ? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
: 'bg-indigo-650 border-indigo-500 text-white hover:bg-indigo-600'
- }`}
+ }`}
title={muteNotifications ? "Bật thông báo đẩy" : "Tắt thông báo đẩy"}
>
{muteNotifications ? (
@@ -1186,7 +1190,7 @@ return (
{/* Quick Nav Links */}
-
@@ -1199,11 +1203,10 @@ return (
handleSelectTab('tours')}
- className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${
- activeTab === 'tours'
- ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
+ className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'tours'
+ ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
- }`}
+ }`}
>
@@ -1219,11 +1222,10 @@ return (
handleSelectTab('photos')}
- className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${
- activeTab === 'photos'
- ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
+ className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'photos'
+ ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
- }`}
+ }`}
>
@@ -1239,11 +1241,10 @@ return (
handleSelectTab('chats')}
- className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${
- activeTab === 'chats'
- ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
+ className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'chats'
+ ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
- }`}
+ }`}
>
@@ -1258,11 +1259,10 @@ return (
handleSelectTab('connections')}
- className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${
- activeTab === 'connections'
- ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
+ className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'connections'
+ ? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
- }`}
+ }`}
>
@@ -1306,12 +1306,11 @@ return (
)}
{/* Tab content renders here */}
-
-
+ }`}>
+
{/* TAB 1: MY TOURS */}
{activeTab === 'tours' && (
@@ -1332,7 +1331,7 @@ return (
Chưa có hành trình nào
Bạn chưa tham gia bất kỳ hành trình nào. Hãy bắt đầu bằng cách tìm các hành trình công khai hoặc tạo chuyến đi mới.
-
@@ -1352,11 +1351,11 @@ return (
})();
const participant = tour.participants?.find((p: any) => p.userId === user?.id);
- const roleLabel = participant?.role === 'OWNER' ? 'Chủ tour' :
- participant?.role === 'MANAGER' ? 'Quản lý' : 'Thành viên';
+ const roleLabel = participant?.role === 'OWNER' ? 'Chủ tour' :
+ participant?.role === 'MANAGER' ? 'Quản lý' : 'Thành viên';
return (
-
@@ -1381,7 +1380,7 @@ return (
{tour.title}
-
+
{tour.description && (
{tour.description}
@@ -1443,14 +1442,14 @@ return (
)}
Chụp ảnh
-
- handleNavigateToItinerary(tour)}
- className="flex-1 py-2 px-2 bg-slate-900 hover:bg-slate-800 text-slate-850 hover:text-white rounded-xl text-xs font-bold transition-all border border-slate-800 hover:border-slate-700 flex items-center justify-center gap-1"
- >
- Chi tiết hành trình
-
-
+
+ handleNavigateToItinerary(tour)}
+ className="flex-1 py-2 px-2 bg-slate-900 hover:bg-slate-800 text-slate-850 hover:text-white rounded-xl text-xs font-bold transition-all border border-slate-800 hover:border-slate-700 flex items-center justify-center gap-1"
+ >
+ Chi tiết hành trình
+
+
{/* Emergency Share Button - moved to bottom */}
@@ -1502,31 +1501,28 @@ return (
setConnectionSubTab('list')}
- className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all ${
- connectionSubTab === 'list'
- ? 'bg-indigo-600 text-white shadow-md'
+ className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all ${connectionSubTab === 'list'
+ ? 'bg-indigo-600 text-white shadow-md'
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
- }`}
+ }`}
>
Danh sách kết nối
setConnectionSubTab('search')}
- className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all flex items-center gap-1.5 ${
- connectionSubTab === 'search'
- ? 'bg-indigo-600 text-white shadow-md'
+ className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all flex items-center gap-1.5 ${connectionSubTab === 'search'
+ ? 'bg-indigo-600 text-white shadow-md'
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
- }`}
+ }`}
>
Tìm thành viên mới
setConnectionSubTab('pending')}
- className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all relative ${
- connectionSubTab === 'pending'
- ? 'bg-indigo-600 text-white shadow-md'
+ className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all relative ${connectionSubTab === 'pending'
+ ? 'bg-indigo-600 text-white shadow-md'
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
- }`}
+ }`}
>
Yêu cầu chờ duyệt
{receivedRequests.length > 0 && (
@@ -1557,15 +1553,15 @@ return (
{connections.map((conn) => {
const connUser = conn.targetUser;
return (
-
{connUser.avatar ? (
-
) : (
@@ -1575,11 +1571,10 @@ return (
{connUser.name}
{connUser.email}
-
+ }`}>
{conn.type === 'FAMILY' ? t('familyGroup') : t('friends')}
@@ -1661,15 +1656,15 @@ return (
const statusText = getConnectionStatusText(usr.id);
return (
-
{usr.avatar ? (
-
) : (
@@ -1683,11 +1678,10 @@ return (
{statusText ? (
-
+ }`}>
{statusText}
) : (
@@ -1724,15 +1718,15 @@ return (
) : (
{receivedRequests.map((req) => (
-
{req.requester?.avatar ? (
-
) : (
@@ -1778,15 +1772,15 @@ return (
) : (
{sentRequests.map((req) => (
-
{req.receiver?.avatar ? (
-
) : (
@@ -1822,17 +1816,17 @@ return (
)}
-{/* TAB 4: REALTIME CHAT */}
- {activeTab === 'chats' && (
-
-
+ {/* TAB 4: REALTIME CHAT */}
+ {activeTab === 'chats' && (
+
+
{/* Chats List sidebar: show if not mobile OR if mobile and no active chat user */}
{(!isMobile || !activeChatUser) && (
Chọn người hội thoại
-
+
{connections.length === 0 ? (
@@ -1847,16 +1841,15 @@ return (
handleSelectChatUser(connUser)}
- className={`w-full p-3 rounded-xl flex items-center gap-3 transition-all text-left ${
- isActive
- ? 'bg-indigo-650 text-white shadow-md'
+ className={`w-full p-3 rounded-xl flex items-center gap-3 transition-all text-left ${isActive
+ ? 'bg-indigo-650 text-white shadow-md'
: 'text-slate-350 hover:bg-slate-850/40 hover:text-slate-100'
- }`}
+ }`}
>
{connUser.avatar ? (
-
) : (
@@ -1902,9 +1895,9 @@ return (
)}
{activeChatUser.avatar ? (
-
) : (
@@ -1931,20 +1924,19 @@ return (
chatMessages.map((msg) => {
const isMe = msg.senderId === user.id;
return (
-
-
+ }`}>
{msg.attachmentUrl && (
-
@@ -2024,11 +2015,11 @@ return (
)}
{/* Chat Input form */}
-
)}
- {/* Emergency Share Configuration Modal */}
- {sharingTour && (
-
-
- {/* Modal Header */}
-
-
-
-
{t('emergencyShare')}
-
-
setSharingTour(null)}
- className="p-2 hover:bg-slate-800 rounded-xl text-slate-400 hover:text-white transition-all active:scale-95"
- >
-
-
-
-
- {/* Modal Body */}
-
-
-
{sharingTour.title}
-
{t('emergencyShareTooltip')}
-
-
- {loadingShare ? (
-
-
- {t('loading')}
-
- ) : (
- <>
- {/* Share Activation Toggle */}
-
-
-
Kích hoạt đường dẫn cứu hộ
+ {/* Emergency Share Configuration Modal */}
+ {sharingTour && (
+
+
+ {/* Modal Header */}
+
+
+
+
{t('emergencyShare')}
- {shareStatus && (
-
- handleToggleShare(e.target.checked)}
- className="sr-only peer"
- />
-
-
+
setSharingTour(null)}
+ className="p-2 hover:bg-slate-800 rounded-xl text-slate-400 hover:text-white transition-all active:scale-95"
+ >
+
+
+
+
+ {/* Modal Body */}
+
+
+
{sharingTour.title}
+
{t('emergencyShareTooltip')}
+
+
+ {loadingShare ? (
+
+
+ {t('loading')}
+
+ ) : (
+ <>
+ {/* Share Activation Toggle */}
+
+
+ Kích hoạt đường dẫn cứu hộ
+
+ {shareStatus && (
+
+ handleToggleShare(e.target.checked)}
+ className="sr-only peer"
+ />
+
+
+ )}
+
+
+ {shareStatus?.isEnabled && (
+ <>
+ {/* Configuration: Language and Theme selectors */}
+
+
+ {t('languageSelect')}
+ changeLanguage(e.target.value as any)}
+ className="w-full bg-slate-950 border border-slate-800 text-white rounded-xl px-3 py-2.5 text-xs font-bold focus:outline-none cursor-pointer"
+ >
+ Tiếng Việt
+ English
+ 中文
+
+
+
+
+ {t('themeSelect')}
+ changeTheme(e.target.value as any)}
+ className="w-full bg-slate-950 border border-slate-800 text-white rounded-xl px-3 py-2.5 text-xs font-bold focus:outline-none cursor-pointer"
+ >
+ {t('themeLight')}
+ {t('themeDark')}
+ {t('themeSystem')}
+
+
+
+
+ {/* Shareable Link Input with Copy button */}
+
+
Đường dẫn khẩn cấp:
+
+
+ {
+ navigator.clipboard.writeText(`${window.location.origin}/journey/${shareStatus.token}?lang=${lang}&theme=${theme}`);
+ notify({ title: 'Thành công', message: 'Đã sao chép liên kết!', type: 'success' });
+ }}
+ className="bg-rose-600 hover:bg-rose-700 text-white font-bold px-4 py-2.5 rounded-xl text-xs transition-all active:scale-95 shrink-0"
+ >
+ {t('copyShareLink')}
+
+
+
+ >
+ )}
+ >
)}
- {shareStatus?.isEnabled && (
- <>
- {/* Configuration: Language and Theme selectors */}
-
-
- {t('languageSelect')}
- changeLanguage(e.target.value as any)}
- className="w-full bg-slate-950 border border-slate-800 text-white rounded-xl px-3 py-2.5 text-xs font-bold focus:outline-none cursor-pointer"
- >
- Tiếng Việt
- English
- 中文
-
-
-
-
- {t('themeSelect')}
- changeTheme(e.target.value as any)}
- className="w-full bg-slate-950 border border-slate-800 text-white rounded-xl px-3 py-2.5 text-xs font-bold focus:outline-none cursor-pointer"
- >
- {t('themeLight')}
- {t('themeDark')}
- {t('themeSystem')}
-
-
-
-
- {/* Shareable Link Input with Copy button */}
-
-
Đường dẫn khẩn cấp:
-
-
- {
- navigator.clipboard.writeText(`${window.location.origin}/journey/${shareStatus.token}?lang=${lang}&theme=${theme}`);
- notify({ title: 'Thành công', message: 'Đã sao chép liên kết!', type: 'success' });
- }}
- className="bg-rose-600 hover:bg-rose-700 text-white font-bold px-4 py-2.5 rounded-xl text-xs transition-all active:scale-95 shrink-0"
- >
- {t('copyShareLink')}
-
-
-
- >
- )}
- >
- )}
-
-
- {/* Modal Footer */}
-
- setSharingTour(null)}
- className="py-2.5 px-6 bg-slate-800 hover:bg-slate-700 text-white font-bold rounded-xl text-xs transition-all active:scale-95"
- >
- Đóng
-
-
-
-
- )}
+ {/* Modal Footer */}
+
+ setSharingTour(null)}
+ className="py-2.5 px-6 bg-slate-800 hover:bg-slate-700 text-white font-bold rounded-xl text-xs transition-all active:scale-95"
+ >
+ Đóng
+
+
+
+
+ )}
diff --git a/frontend/src/pages/SignupPage.tsx b/frontend/src/pages/SignupPage.tsx
index f1d2e08..3b6ca8a 100644
--- a/frontend/src/pages/SignupPage.tsx
+++ b/frontend/src/pages/SignupPage.tsx
@@ -1,5 +1,7 @@
import React, { useState, useEffect } from 'react';
import { User, Mail, Lock, ArrowRight, ChevronLeft, Phone, MapPin, ShieldCheck } from 'lucide-react';
+import { Capacitor } from '@capacitor/core';
+import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
interface SignupPageProps {
onBack: () => void;
@@ -69,8 +71,67 @@ const SignupPage: React.FC
= ({ onBack, onSuccess }) => {
}
};
+ const handleNativeGoogleLogin = async () => {
+ setError('');
+ setIsLoading(true);
+ try {
+ const user = await GoogleAuth.signIn();
+ console.log('[SignupPage] Native Google user received:', user);
+
+ const idToken = user.authentication.idToken;
+ if (!idToken) {
+ throw new Error('Không nhận được token từ Google.');
+ }
+
+ const response = await fetch(`/api/v1/auth/google`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ credential: idToken }),
+ });
+
+ const data = await response.json();
+ if (!response.ok) {
+ throw new Error(data.message || 'Đăng ký bằng Google thất bại');
+ }
+
+ localStorage.removeItem('guest_token');
+ localStorage.removeItem('guest_user');
+ localStorage.setItem('token', data.access_token);
+ localStorage.setItem('user', JSON.stringify(data.user));
+
+ const pendingInviteToken = localStorage.getItem('pendingInviteToken');
+ if (pendingInviteToken) {
+ console.log('[SignupPage] Auto-joining tour with pending token after Google signup');
+ await fetch(`/api/v1/tours/join-by-token`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${data.access_token}`,
+ },
+ body: JSON.stringify({ token: pendingInviteToken }),
+ }).then(res => {
+ if (res.ok) {
+ localStorage.removeItem('pendingInviteToken');
+ console.log('[SignupPage] Successfully joined tour after Google signup');
+ } else {
+ console.warn('[SignupPage] Failed to join tour after Google signup:', res.status);
+ }
+ }).catch((e) => console.error('Lỗi tự động gia nhập:', e));
+ }
+
+ onSuccess();
+ } catch (err: any) {
+ console.error('[SignupPage] Native Google signup error:', err);
+ if (err?.message !== 'Sign in window was closed' && err?.message !== '12501') {
+ setError(err.message || 'Đăng ký bằng Google thất bại');
+ }
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
useEffect(() => {
- if (step !== 'form') return;
+ if (step !== 'form' || Capacitor.isNativePlatform()) return;
const timer = setTimeout(() => {
if (typeof window !== 'undefined' && (window as any).google) {
@@ -313,7 +374,23 @@ const SignupPage: React.FC = ({ onBack, onSuccess }) => {
Hoặc
-
+ {Capacitor.isNativePlatform() ? (
+
+
+
+
+ Đăng ký bằng Google
+
+ ) : (
+
+ )}
>
)}
diff --git a/frontend/src/pages/TourDetailPage.tsx b/frontend/src/pages/TourDetailPage.tsx
index 60bfeeb..eebea28 100644
--- a/frontend/src/pages/TourDetailPage.tsx
+++ b/frontend/src/pages/TourDetailPage.tsx
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useMemo, useRef } from 'react';
import { io } from 'socket.io-client';
+import { Capacitor } from '@capacitor/core';
import { jsPDF } from 'jspdf';
import autoTable from 'jspdf-autotable';
import { robotoBase64, robotoBoldBase64 } from '../utils/pdfFont';
@@ -1571,7 +1572,9 @@ export const TourDetailPage = ({
useEffect(() => {
if (!currentTour) return;
- const socket = io(); // Kết nối qua Proxy của Vite (cùng origin)
+ const socket = Capacitor.isNativePlatform()
+ ? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
+ : io(); // Kết nối qua Proxy của Vite (cùng origin)
socket.on('connect', () => {
socket.emit('joinTour', currentTour.id);
@@ -1910,7 +1913,7 @@ export const TourDetailPage = ({
{/* Top Navigation Bar */}
-
+ setActiveTab('plan') : onBack} className="p-2 hover:bg-[var(--background)] rounded-full transition-colors">
@@ -2210,7 +2213,7 @@ export const TourDetailPage = ({
{/* Main Content Area - Điều chỉnh max-width khi ở chế độ bản đồ */}
{/* Tab Switcher */}
- {!(activeTab === 'plan' && viewMode === 'map') && (
+ {!(activeTab === 'plan' && viewMode === 'map') && activeTab !== 'chat' && (
{tabs.map((tab) => (
rewriteUrls(item, backendUrl));
+ }
+ if (typeof obj === 'object') {
+ const newObj: any = {};
+ for (const key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
+ newObj[key] = rewriteUrls(obj[key], backendUrl);
+ }
+ }
+ return newObj;
+ }
+ return obj;
+}
+
+if (Capacitor.isNativePlatform()) {
+ // Initialize native Google Login client to prevent NullPointerException crashes
+ try {
+ GoogleAuth.initialize({
+ clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID || '639044397050-7hair384u6lle941h033trut1s3q47l4.apps.googleusercontent.com',
+ scopes: ['profile', 'email'],
+ grantOfflineAccess: true,
+ });
+ console.log('[Native OAuth] GoogleAuth initialized successfully.');
+ } catch (e) {
+ console.error('[Native OAuth] Failed to initialize GoogleAuth client:', e);
+ }
+
+ // Request native local notification permission on startup
+ try {
+ LocalNotifications.requestPermissions().then(result => {
+ console.log('[LocalNotifications] Permissions requested:', result);
+ });
+ } catch (e) {
+ console.error('[LocalNotifications] Failed to request permissions:', e);
+ }
+
+ const backendUrl = import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn';
+
+ const originalFetch = window.fetch;
+ window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise => {
+ let url = input;
+ if (typeof url === 'string') {
+ if (url.startsWith('/api/') || url.startsWith('/uploads/')) {
+ url = `${backendUrl}${url}`;
+ }
+ } else if (url instanceof URL) {
+ if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/uploads/')) {
+ url = new URL(`${backendUrl}${url.pathname}${url.search}`);
+ }
+ } else if (url && typeof url === 'object' && 'url' in url) {
+ // If it is a Request object
+ const req = url as Request;
+ const reqUrl = req.url;
+ if (reqUrl.startsWith('/') || new URL(reqUrl).pathname.startsWith('/api/') || new URL(reqUrl).pathname.startsWith('/uploads/')) {
+ const targetUrl = reqUrl.startsWith('/') ? `${backendUrl}${reqUrl}` : reqUrl.replace(new URL(reqUrl).origin, backendUrl);
+ url = new Request(targetUrl, req);
+ }
+ }
+
+ const response = await originalFetch(url, init);
+
+ // Override the json method of this specific response instance
+ const originalJson = response.json;
+ response.json = async () => {
+ const data = await originalJson.call(response);
+ return rewriteUrls(data, backendUrl);
+ };
+
+ return response;
+ };
+}
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 320ea9b..9a798e5 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -23,6 +23,33 @@ export default defineConfig(({ mode }) => {
'@': path.resolve(__dirname, './src'),
},
},
+ build: {
+ chunkSizeWarningLimit: 1500,
+ rollupOptions: {
+ output: {
+ manualChunks(id) {
+ if (id.includes('node_modules')) {
+ if (id.includes('react') || id.includes('scheduler')) {
+ return 'vendor-react';
+ }
+ if (id.includes('leaflet')) {
+ return 'vendor-maps';
+ }
+ if (id.includes('jspdf')) {
+ return 'vendor-pdf';
+ }
+ if (id.includes('lucide-react')) {
+ return 'vendor-icons';
+ }
+ if (id.includes('quill')) {
+ return 'vendor-editor';
+ }
+ return 'vendor-others';
+ }
+ }
+ }
+ }
+ },
server: {
port: 3002,
host: true,
diff --git a/google_oauth_plan.md b/google_oauth_plan.md
new file mode 100644
index 0000000..9491c2b
--- /dev/null
+++ b/google_oauth_plan.md
@@ -0,0 +1,184 @@
+# Plan: Đăng nhập / Đăng ký bằng Tài khoản Google (Google OAuth)
+
+Cho phép người dùng tạo tài khoản hoặc đăng nhập nhanh chóng bằng tài khoản Google đang được sử dụng trên thiết bị, không cần nhập email/mật khẩu thủ công.
+
+---
+
+## Luồng hoạt động
+
+```
+1. Người dùng nhấn nút "Đăng nhập bằng Google"
+2. Frontend redirect → Backend endpoint /api/v1/auth/google
+3. Backend redirect → Google OAuth Consent Screen
+4. Google xác thực xong → callback về /api/v1/auth/google/callback
+5. Backend tìm user theo googleId (hoặc email):
+ - Nếu đã tồn tại → đăng nhập, cấp JWT
+ - Nếu chưa có → tạo tài khoản mới, cấp JWT
+6. Backend redirect về Frontend kèm JWT trong query param
+7. Frontend đọc JWT → lưu localStorage → điều hướng vào app
+```
+
+---
+
+## Open Questions
+
+> [!IMPORTANT]
+> Trước khi thực hiện, bạn cần:
+> 1. Tạo **Google OAuth 2.0 Client** tại [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
+> 2. Điền **Authorized redirect URI**: `http://localhost:3001/api/v1/auth/google/callback`
+> 3. Cung cấp `GOOGLE_CLIENT_ID` và `GOOGLE_CLIENT_SECRET` để thêm vào `.env`
+
+---
+
+## Proposed Changes
+
+### Backend
+
+---
+
+#### [MODIFY] [schema.prisma](file:///home/locpham/travelplanning/backend/prisma/schema.prisma)
+- Thêm trường `googleId String? @unique` vào model `User` để lưu Google Account ID (unique identifier của từng tài khoản Google).
+
+```diff
+ model User {
+ id String @id @default(uuid())
+ email String? @unique
++ googleId String? @unique
+ passwordHash String?
+ ...
+```
+
+- Chạy migration: `npm run db:migrate`
+
+---
+
+#### [MODIFY] [main.ts](file:///home/locpham/travelplanning/backend/src/main.ts)
+**1. Cài đặt thêm dependencies:**
+```bash
+npm install passport-google-oauth20 @types/passport-google-oauth20 -w backend
+```
+
+**2. Import & cấu hình Google Strategy (thêm vào đầu file):**
+```typescript
+import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
+import * as passport from 'passport';
+```
+
+**3. Thêm 2 endpoint mới vào `AuthController`:**
+
+- `GET /auth/google` — Khởi động OAuth flow, redirect sang Google
+- `GET /auth/google/callback` — Google callback; tìm/tạo user, cấp JWT rồi redirect về frontend với token
+
+```typescript
+@Get('google')
+async googleAuth(@Req() req: any, @Res() res: any) {
+ // Redirect đến Google login
+ const params = new URLSearchParams({
+ client_id: process.env.GOOGLE_CLIENT_ID!,
+ redirect_uri: `${process.env.BACKEND_URL}/api/v1/auth/google/callback`,
+ response_type: 'code',
+ scope: 'email profile',
+ access_type: 'offline',
+ });
+ res.redirect(`https://accounts.google.com/o/oauth2/v2/auth?${params}`);
+}
+
+@Get('google/callback')
+async googleCallback(@Query('code') code: string, @Res() res: any) {
+ // 1. Exchange code for tokens với Google
+ // 2. Lấy profile (googleId, email, name, picture)
+ // 3. Upsert user theo googleId hoặc email
+ // 4. Tạo JWT
+ // 5. Redirect về frontend: http://localhost:5173/auth/callback?token=...&user=...
+}
+```
+
+> [!NOTE]
+> Không dùng `passport.authenticate()` middleware để đơn giản hóa, thay vào đó dùng `fetch` trực tiếp tới Google Token endpoint để trao đổi `code` lấy `access_token`, sau đó gọi Google People API để lấy profile.
+
+**4. Thêm biến môi trường mới vào `.env`:**
+```env
+GOOGLE_CLIENT_ID=your_client_id
+GOOGLE_CLIENT_SECRET=your_client_secret
+BACKEND_URL=http://localhost:3001
+FRONTEND_URL=http://localhost:5173
+```
+
+---
+
+### Frontend
+
+---
+
+#### [MODIFY] [App.tsx](file:///home/locpham/travelplanning/frontend/src/App.tsx)
+- Thêm xử lý route `/auth/callback` (hoặc dùng `useEffect` kiểm tra query params khi app mount): đọc `?token=` và `?user=` từ URL, lưu vào `localStorage`, sau đó điều hướng vào trang explore.
+
+---
+
+#### [MODIFY] [LoginModal.tsx](file:///home/locpham/travelplanning/frontend/src/components/LoginModal.tsx)
+- Thêm nút **"Đăng nhập bằng Google"** ở phía dưới form, tách biệt bằng divider `— hoặc —`.
+- Khi nhấn: `window.location.href = '/api/v1/auth/google'`
+
+```tsx
+{/* Divider */}
+
+
+{/* Google Button */}
+ window.location.href = '/api/v1/auth/google'}
+ className="w-full flex items-center justify-center gap-3 bg-white border border-gray-200 hover:bg-gray-50 text-gray-700 font-semibold py-4 rounded-2xl shadow-sm transition-all"
+>
+
+ Đăng nhập bằng Google
+
+```
+
+---
+
+#### [MODIFY] [SignupPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/SignupPage.tsx)
+- Thêm nút "Đăng ký nhanh bằng Google" tương tự ở phần `step === 'form'`.
+- Cùng hành động: redirect sang `/api/v1/auth/google`.
+
+---
+
+## Sơ đồ kiến trúc
+
+```mermaid
+sequenceDiagram
+ participant U as Người dùng
+ participant FE as Frontend
+ participant BE as Backend
+ participant G as Google OAuth
+
+ U->>FE: Nhấn "Đăng nhập bằng Google"
+ FE->>BE: GET /api/v1/auth/google
+ BE->>G: Redirect → Google Consent Screen
+ G->>U: Hiển thị chọn tài khoản
+ U->>G: Chọn tài khoản
+ G->>BE: Callback với authorization code
+ BE->>G: Exchange code → access_token
+ BE->>G: GET profile (googleId, email, name, avatar)
+ BE->>BE: Upsert User (tìm theo googleId hoặc email)
+ BE->>BE: Tạo JWT
+ BE->>FE: Redirect về /auth/callback?token=...&user=...
+ FE->>FE: Lưu token/user vào localStorage
+ FE->>U: Điều hướng vào Explore Map
+```
+
+---
+
+## Verification Plan
+
+### Automated Tests
+- `npm run build -w frontend` để kiểm tra TypeScript.
+
+### Manual Verification
+1. Nhấn "Đăng nhập bằng Google" → chọn tài khoản Google → kiểm tra được điều hướng vào app.
+2. Đăng xuất → đăng nhập lại bằng cùng tài khoản Google → kiểm tra không bị tạo user mới.
+3. Người dùng đã có tài khoản email trùng → kiểm tra được hợp nhất (merge) với tài khoản hiện có.
+4. Kiểm tra `googleId` được lưu vào DB.
diff --git a/implementation_plan.md b/implementation_plan.md
new file mode 100644
index 0000000..813f0b0
--- /dev/null
+++ b/implementation_plan.md
@@ -0,0 +1,78 @@
+# Plan to Implement Like-Based Photo Selection, Displays, and Mobile UI Enhancements
+
+Highlight photos with more likes across different displays and optimize the public photo modal's mobile UI layout.
+
+---
+
+## Proposed Changes
+
+### 1. Public Photo Modal Mobile UI Layout & Fixes
+
+#### [MODIFY] [PublicPhotoModal.tsx](file:///home/locpham/travelplanning/frontend/src/components/PublicPhotoModal.tsx)
+- **Fixed Photo and Scrollable Comments**:
+ - Remove parent modal container vertical scrolling on mobile (`overflow-y-auto` -> `overflow-hidden`).
+ - Set the parent container layout to `flex flex-col h-[90vh] md:h-[85vh] overflow-hidden`.
+ - The photo container (`h-[45vh]`) and mobile uploader details container will remain static/fixed at the top.
+ - Set the comments panel container to `flex-1 min-h-0 flex flex-col` and the comments list to `flex-1 overflow-y-auto` so only the comments scroll on mobile.
+- **Remove Comments Header on Mobile**:
+ - Add responsive classes to the comment header (`hidden md:block`) to hide the "Bình luận cộng đồng" / "bình luận từ cộng đồng" title banner on mobile, maximizing space.
+- **Style Uploader Details**:
+ - Reduce font size and remove bold style for the "Người đăng" (Uploader name) elements.
+ - Desktop uploader text: change from `font-semibold` to `text-xs`.
+ - Mobile uploader text: change from `text-sm font-semibold text-white` to `text-xs text-slate-200`.
+- **Safe Area Like Button**:
+ - Shift the absolute top position of the Like button to account for safe area insets: `top-[calc(1rem+env(safe-area-inset-top,0px))]`. This prevents browser address bars or notches from clipping it.
+
+---
+
+### 2. Landing Page Like-Based Sorting
+
+#### [MODIFY] [LandingPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/LandingPage.tsx)
+- In `fetchPublicPhotos`, sort the fetched `publicPhotos` array based on the number of likes (`likedUserIds.length`) in descending order.
+- This ensures:
+ 1. The cycling background images naturally present the most-liked public photos first.
+ 2. The gallery previews at the bottom display the top 8 most-liked photos from the community.
+
+---
+
+### 3. Tour Banner Image Selection
+
+#### [MODIFY] [TourDetailPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/TourDetailPage.tsx)
+- Replace the simple first-photo check for `coverImage` with a function that retrieves the photo with the most likes in the tour.
+- If there are no photos in the tour, fall back to the default Unsplash placeholder cover image.
+
+---
+
+### 4. Auto-Select Most Liked Photo for Display
+
+#### [MODIFY] [ExploreMap.tsx](file:///home/locpham/travelplanning/frontend/src/pages/ExploreMap.tsx)
+- In `groupedPhotos` memo, sort each location's photo array so that photos with the most likes appear first.
+- This ensures the map pin thumbnail bubble displays the most-liked photo at that coordinate, and clicking it displays that photo as the default.
+
+#### [MODIFY] [MyPhotosPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/MyPhotosPage.tsx)
+- Define a helper function `getMostLikedPhoto(photos)` that returns the photo with the most likes.
+- In the `useEffect` that updates `selectedPhotoForDisplay`, use this helper to default-select the most liked photo from the filtered list.
+
+#### [MODIFY] [TourDetailPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/TourDetailPage.tsx)
+- Define the same helper function `getMostLikedPhoto(photos)`.
+- Update the default photo selection inside both `useEffect` hooks (the one listening to `filteredPhotos` and the one listening to `currentTour`/`legs` changes) to select the photo with the most likes using this helper.
+
+---
+
+## Verification Plan
+
+### Automated Tests
+- Run `npm run build -w frontend` to verify that there are no compilation or syntax errors.
+
+### Manual Verification
+- **Mobile Public Photo Modal**:
+ 1. View a photo on mobile browser/emulator.
+ 2. Verify only the comments scroll, and the header label is hidden.
+ 3. Verify the Like button position is adjusted.
+ 4. Verify the Uploader text size is reduced and normal.
+- **Landing Page background & gallery**:
+ 1. Open the landing page. Verify that the previews show the most liked photos first.
+- **Tour Banner**:
+ 1. Verify the tour banner updates to show the photo with the most likes.
+- **Map Marker / Photo Timeline default**:
+ 1. Click map marker and verify most liked photo is active by default.
diff --git a/implementation_plan_11features.md b/implementation_plan_11features.md
new file mode 100644
index 0000000..a158eff
--- /dev/null
+++ b/implementation_plan_11features.md
@@ -0,0 +1,166 @@
+# Kế hoạch triển khai: 11 Tính năng mới (Bổ sung Đa ngôn ngữ & Giao diện Sáng/Tối)
+
+Kế hoạch này phác thảo các thay đổi về cơ sở dữ liệu (Prisma Schema), các API Endpoint ở Backend (NestJS), các Component và trang ở Frontend (React) để hiện thực hóa 11 tính năng mới theo yêu cầu của bạn.
+
+---
+
+## User Review Required
+
+> [!IMPORTANT]
+> - **Hệ thống đa ngôn ngữ (Tiếng Việt, Tiếng Anh, Tiếng Trung)**: Chúng tôi sẽ triển khai một hook dịch thuật tinh gọn `useTranslation` dạng từ điển lưu trữ cục bộ ở Frontend. Toàn bộ các tiêu đề, nhãn (labels), nút bấm, thông báo toast và văn bản tĩnh trong dự án sẽ được ánh xạ qua hook này dựa trên ngôn ngữ được lựa chọn. Lựa chọn ngôn ngữ sẽ được lưu trữ vào `localStorage` để giữ trạng thái sau khi tải lại trang.
+> - **Cơ chế Giao diện Sáng / Tối (Light / Dark Theme)**: Hệ thống sẽ hỗ trợ 3 tùy chọn: Sáng (Light), Tối (Dark), và theo Hệ thống (System default, sử dụng `prefers-color-scheme` để tự động đổi màu theo hệ điều hành). Chúng tôi sẽ tích hợp các class tiện ích Tailwind CSS v4 (như `dark:bg-slate-900`, `dark:text-slate-100`, `dark:border-slate-800`) vào tất cả các component chính để giao diện đồng bộ hoàn hảo.
+> - **Cơ chế lọc ảnh khiêu dâm & Làm mờ khuôn mặt**: Xử lý trực tiếp trên trình duyệt (Client-side) qua TensorFlow.js trước khi tải lên để đảm bảo tối ưu hiệu năng backend.
+> - **Tài khoản Admin quản trị hệ thống bằng Secret Key**: Đọc `ADMIN_SECRET_KEY` từ `.env`. Ở Frontend, người dùng có thể kích hoạt quyền Admin tức thời bằng cách nhập chuỗi khóa này để được promote lên `isAdmin: true` trong Database.
+
+---
+
+## Open Questions
+
+> [!WARNING]
+> - Bạn có muốn lưu tùy chọn ngôn ngữ trực tiếp vào tài khoản User ở Database (để khi đăng nhập trên thiết bị khác thì tự động áp dụng ngôn ngữ đó) hay chỉ cần lưu ở `localStorage` trình duyệt là đủ?
+> - Ngoài các ngôn ngữ Tiếng Việt, Tiếng Anh, Tiếng Trung, bạn có dự định mở rộng thêm ngôn ngữ nào khác trong tương lai không?
+
+---
+
+## Proposed Changes
+
+### 1. Thay đổi Cơ sở dữ liệu (`backend/prisma/schema.prisma`)
+
+Chúng ta sẽ bổ sung các Model mới để lưu trữ: Bộ lọc từ khóa, Cấu hình bộ lọc hình ảnh, Đánh giá Owner, và Mã chia sẻ hành trình.
+
+#### [MODIFY] [schema.prisma](file:///home/locpham/travelplanning/backend/prisma/schema.prisma)
+- Thêm model `WordFilter` để cấu hình bộ lọc từ khóa cấm.
+- Thêm model `ModerationSetting` để lưu trạng thái cấu hình lọc của hệ thống.
+- Thêm model `TourRating` để lưu đánh giá 5 sao cho Owner/Manager từ các thành viên.
+- Thêm model `TourShare` để quản lý liên kết chia sẻ hành trình khẩn cấp.
+
+```prisma
+model WordFilter {
+ id String @id @default(uuid())
+ word String @unique
+ replacement String
+ createdAt DateTime @default(now())
+}
+
+model ModerationSetting {
+ id String @id @default(uuid())
+ blockNsfw Boolean @default(false)
+ blurFaces Boolean @default(false)
+}
+
+model TourRating {
+ id String @id @default(uuid())
+ tourId String
+ targetUserId String // Owner/Manager được đánh giá
+ raterUserId String // Người dùng thực hiện đánh giá
+ honesty Int @default(5)
+ transparency Int @default(5)
+ enthusiasm Int @default(5)
+ cheerfulness Int @default(5)
+ seriousness Int @default(5)
+ planning Int @default(5)
+ survival Int @default(5)
+ averageScore Float @default(5.0)
+ comment String? @db.Text
+ createdAt DateTime @default(now())
+
+ tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
+ targetUser User @relation("RatedUser", fields: [targetUserId], references: [id], onDelete: Cascade)
+ raterUser User @relation("RatingUser", fields: [raterUserId], references: [id], onDelete: Cascade)
+
+ @@unique([tourId, targetUserId, raterUserId])
+}
+
+model TourShare {
+ id String @id @default(uuid())
+ tourId String @unique
+ token String @unique @default(uuid())
+ isEnabled Boolean @default(true)
+ createdAt DateTime @default(now())
+
+ tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
+}
+```
+
+---
+
+### 2. Backend API (`backend/src/main.ts`)
+
+#### [MODIFY] [main.ts](file:///home/locpham/travelplanning/backend/src/main.ts)
+- Triển khai đầy đủ các endpoint như trong kế hoạch trước đó:
+ - `DELETE /api/v1/public-photos/comments/:id`
+ - Tích hợp bộ lọc từ khóa cấm ở các API tạo bài đăng/tin nhắn/bình luận.
+ - API cài đặt bộ lọc ảnh và text của Admin (`/api/v1/admin/moderation`, `/api/v1/admin/word-filters`).
+ - API Đánh giá Owner/Manager (`/api/v1/tours/:tourId/ratings`) và Leaderboard uy tín (`/api/v1/users/trusted`).
+ - API kích hoạt Admin bằng secret key (`/api/v1/auth/promote-admin`).
+ - API chia sẻ hành trình khẩn cấp (`/api/v1/tours/:tourId/share`, `/api/v1/tours/share/:token`).
+
+---
+
+### 3. Giao diện Frontend (`frontend/src/...`)
+
+#### [NEW] [useTranslation.ts](file:///home/locpham/travelplanning/frontend/src/hooks/useTranslation.ts)
+- Tạo hook `useTranslation` để quản lý đa ngôn ngữ:
+ - Khai báo từ điển ngôn ngữ `translations` chứa các bản dịch Tiếng Việt (VI), Tiếng Anh (EN), Tiếng Trung (ZH).
+ - Hỗ trợ hàm dịch `t(key: string)` và các hàm chuyển đổi ngôn ngữ, tự động đồng bộ giá trị với `localStorage.getItem('language')`.
+ - Dịch các tiêu đề, thông báo, nhãn, nút bấm trong toàn bộ ứng dụng sang 3 ngôn ngữ tương ứng.
+
+#### [NEW] [useTheme.ts](file:///home/locpham/travelplanning/frontend/src/hooks/useTheme.ts)
+- Tạo hook `useTheme` để quản lý giao diện Sáng/Tối:
+ - Quản lý trạng thái theme (`light`, `dark`, `system`).
+ - Nếu chọn `system`, sử dụng `window.matchMedia('(prefers-color-scheme: dark)')` để lắng nghe thiết lập hệ điều hành của người dùng.
+ - Thêm hoặc xóa class `dark` khỏi thẻ `` hoặc `` của ứng dụng.
+
+#### [MODIFY] [index.css](file:///home/locpham/travelplanning/frontend/src/index.css)
+- Bổ sung cấu hình màu sắc cơ bản cho dark mode: định nghĩa các màu nền và chữ chính cho chế độ tối để đảm bảo độ tương phản tốt nhất và đồng bộ thiết kế.
+
+#### [MODIFY] [ExploreMap.tsx](file:///home/locpham/travelplanning/frontend/src/pages/ExploreMap.tsx), [MemberDashboard.tsx](file:///home/locpham/travelplanning/frontend/src/pages/MemberDashboard.tsx), [LandingPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/LandingPage.tsx)
+- **Tích hợp Dark Mode**: Thêm các lớp CSS Tailwind như `dark:bg-slate-900`, `dark:text-slate-100`, `dark:border-slate-800` vào tất cả các card, danh sách và thanh điều hướng chính.
+- **Thanh công cụ**: Thêm dropdown lựa chọn ngôn ngữ (Tiếng Việt, Tiếng Anh, Tiếng Trung) và nút chuyển đổi giao diện (Sáng/Tối/Hệ thống) ở Sidebar/Header cạnh nút Đăng xuất hoặc trong Menu Cài đặt của Admin.
+- **Áp dụng Đa ngôn ngữ**: Thay thế toàn bộ text hiển thị tĩnh bằng hàm dịch `t('key')` (ví dụ: `t('explore')`, `t('logout')`, `t('trusted_members')`,...).
+
+#### [MODIFY] [ItineraryTimeline.tsx](file:///home/locpham/travelplanning/frontend/src/components/ItineraryTimeline.tsx)
+- Bổ sung click vào địa điểm để xem trên bản đồ (gọi `onNavigate`).
+- Áp dụng các lớp Tailwind chế độ tối (`dark:bg-slate-900`, `dark:border-slate-800`, `dark:text-gray-100`) để các thẻ chặng và chi tiết điểm dừng hiển thị hoàn hảo ở Dark Mode.
+- Thay các đoạn text tĩnh bằng đa ngôn ngữ.
+
+#### [MODIFY] [TourDetailPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/TourDetailPage.tsx)
+- Thêm nút "Xuất PDF" (không kèm chi phí) sử dụng `html2pdf.js` từ CDN.
+- Tích hợp Đánh giá ban tổ chức 5 sao.
+- Tích hợp Đa ngôn ngữ và Dark Mode vào toàn bộ trang chi tiết hành trình.
+
+#### [MODIFY] [PublicPhotoModal.tsx](file:///home/locpham/travelplanning/frontend/src/components/PublicPhotoModal.tsx)
+- Cho phép xóa bình luận nếu thỏa mãn điều kiện quyền hạn.
+- Tích hợp Đa ngôn ngữ và Dark Mode.
+
+#### [MODIFY] [CoordinateSelectModal.tsx](file:///home/locpham/travelplanning/frontend/src/components/CoordinateSelectModal.tsx)
+- Ẩn liên kết Leaflet bằng `attributionControl={false}`.
+- Bổ sung ô tìm kiếm địa điểm tích hợp Nominatim API.
+- Tích hợp Dark Mode (bảng kết quả tìm kiếm và các khung modal chuyển sang màu tối phù hợp).
+
+#### [NEW] [ShareJourneyPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/ShareJourneyPage.tsx)
+- Giao diện chia sẻ khẩn cấp, tích hợp Đa ngôn ngữ và hỗ trợ cả 2 chế độ Sáng / Tối.
+
+#### [MODIFY] [App.tsx](file:///home/locpham/travelplanning/frontend/src/App.tsx)
+- Cập nhật logic route `/journey/:token`.
+- Bao bọc ứng dụng để khởi chạy ngôn ngữ và theme mặc định dựa trên cấu hình hệ thống / localStorage khi ứng dụng khởi chạy.
+
+---
+
+## Verification Plan
+
+### Automated Tests
+- Chạy biên dịch toàn bộ hệ thống để phát hiện lỗi TypeScript:
+ - Backend: `npm run build -w backend`
+ - Frontend: `npm run build -w frontend` hoặc chạy bộ kiểm tra TypeScript: `npx tsc --noEmit` ở thư mục frontend.
+
+### Manual Verification
+1. **Kiểm tra Đa ngôn ngữ**:
+ - Chuyển đổi ngôn ngữ sang Tiếng Anh / Tiếng Trung.
+ - Xác nhận tất cả tiêu đề, nhãn, nút bấm, thông báo toast cập nhật sang ngôn ngữ mới.
+2. **Kiểm tra Dark Mode**:
+ - Thay đổi cài đặt sang "Tối". Xác nhận toàn bộ giao diện (kể cả các card trắng ở dashboard, timeline, map modal) chuyển thành màu tối.
+ - Thay đổi cài đặt sang "Hệ thống". Đổi cấu hình hệ điều hành từ Light sang Dark và ngược lại để xác nhận trang web đổi giao diện tương ứng theo thời gian thực.
+3. **Kiểm tra click địa điểm xem bản đồ**: Xác nhận click vào địa điểm timeline tự động nhảy sang tab bản đồ và hiển thị lộ trình.
+4. **Kiểm tra xuất PDF**: Xác nhận xuất lịch trình ra file PDF không chứa thông tin chi phí.
+5. **Kiểm tra xóa bình luận công khai, lọc ảnh & text, chia sẻ khẩn cấp, admin secret key**.
diff --git a/package-lock.json b/package-lock.json
index 5905daa..a907088 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -190,12 +190,6 @@
"fsevents": "2.3.3"
}
},
- "backend/node_modules/reflect-metadata": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
- "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
- "license": "Apache-2.0"
- },
"backend/node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
@@ -207,9 +201,12 @@
"version": "1.0.0",
"dependencies": {
"@capacitor/android": "^8.4.1",
+ "@capacitor/camera": "^8.2.0",
"@capacitor/cli": "^7.6.7",
"@capacitor/core": "^8.4.1",
"@capacitor/geolocation": "^8.2.0",
+ "@capacitor/local-notifications": "^8.2.0",
+ "@codetrix-studio/capacitor-google-auth": "^3.4.0-rc.4",
"date-fns": "^4.4.0",
"jspdf": "^4.2.1",
"jspdf-autotable": "^5.0.8",
@@ -225,6 +222,7 @@
"zustand": "^5.0.1"
},
"devDependencies": {
+ "@capacitor/assets": "^3.0.5",
"@tailwindcss/postcss": "^4.3.1",
"@types/leaflet": "^1.9.12",
"@types/react": "^18.3.12",
@@ -509,6 +507,437 @@
"@capacitor/core": "^8.4.0"
}
},
+ "node_modules/@capacitor/assets": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@capacitor/assets/-/assets-3.0.5.tgz",
+ "integrity": "sha512-ohz/OUq61Y1Fc6aVSt0uDrUdeOA7oTH4pkWDbv/8I3UrPjH7oPkzYhShuDRUjekNp9RBi198VSFdt0CetpEOzw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@capacitor/cli": "^5.3.0",
+ "@ionic/utils-array": "2.1.6",
+ "@ionic/utils-fs": "3.1.7",
+ "@trapezedev/project": "^7.0.10",
+ "commander": "8.3.0",
+ "debug": "4.3.4",
+ "fs-extra": "10.1.0",
+ "node-fetch": "2.7.0",
+ "node-html-parser": "5.4.2",
+ "sharp": "0.32.6",
+ "tslib": "2.6.2",
+ "yargs": "17.7.2"
+ },
+ "bin": {
+ "capacitor-assets": "bin/capacitor-assets"
+ },
+ "engines": {
+ "node": ">=10.3.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/@capacitor/cli": {
+ "version": "5.7.8",
+ "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.7.8.tgz",
+ "integrity": "sha512-qN8LDlREMhrYhOvVXahoJVNkP8LP55/YPRJrzTAFrMqlNJC18L3CzgWYIblFPnuwfbH/RxbfoZT/ydkwgVpMrw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ionic/cli-framework-output": "^2.2.5",
+ "@ionic/utils-fs": "^3.1.6",
+ "@ionic/utils-subprocess": "^2.1.11",
+ "@ionic/utils-terminal": "^2.3.3",
+ "commander": "^9.3.0",
+ "debug": "^4.3.4",
+ "env-paths": "^2.2.0",
+ "kleur": "^4.1.4",
+ "native-run": "^2.0.0",
+ "open": "^8.4.0",
+ "plist": "^3.0.5",
+ "prompts": "^2.4.2",
+ "rimraf": "^4.4.1",
+ "semver": "^7.3.7",
+ "tar": "^6.1.11",
+ "tslib": "^2.4.0",
+ "xml2js": "^0.5.0"
+ },
+ "bin": {
+ "cap": "bin/capacitor",
+ "capacitor": "bin/capacitor"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/@capacitor/cli/node_modules/commander": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
+ "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/@ionic/utils-process": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.11.tgz",
+ "integrity": "sha512-Uavxn+x8j3rDlZEk1X7YnaN6wCgbCwYQOeIjv/m94i1dzslqWhqIHEqxEyeE8HsT5Negboagg7GtQiABy+BLbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ionic/utils-object": "2.1.6",
+ "@ionic/utils-terminal": "2.3.4",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "tree-kill": "^1.2.2",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/@ionic/utils-stream": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.6.tgz",
+ "integrity": "sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/@ionic/utils-subprocess": {
+ "version": "2.1.14",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.14.tgz",
+ "integrity": "sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ionic/utils-array": "2.1.6",
+ "@ionic/utils-fs": "3.1.7",
+ "@ionic/utils-process": "2.1.11",
+ "@ionic/utils-stream": "3.1.6",
+ "@ionic/utils-terminal": "2.3.4",
+ "cross-spawn": "^7.0.3",
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/@ionic/utils-terminal": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz",
+ "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/slice-ansi": "^4.0.0",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "tslib": "^2.0.1",
+ "untildify": "^4.0.0",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/brace-expansion": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz",
+ "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/glob": {
+ "version": "9.3.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
+ "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "minimatch": "^8.0.2",
+ "minipass": "^4.2.4",
+ "path-scurry": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/@capacitor/assets/node_modules/minimatch": {
+ "version": "8.0.7",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.7.tgz",
+ "integrity": "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/minipass": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
+ "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/minizlib/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@capacitor/assets/node_modules/node-addon-api": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
+ "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@capacitor/assets/node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/path-scurry/node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/rimraf": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz",
+ "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^9.2.0"
+ },
+ "bin": {
+ "rimraf": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/sharp": {
+ "version": "0.32.6",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz",
+ "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.2",
+ "node-addon-api": "^6.1.0",
+ "prebuild-install": "^7.1.1",
+ "semver": "^7.5.4",
+ "simple-get": "^4.0.1",
+ "tar-fs": "^3.0.4",
+ "tunnel-agent": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=14.15.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/@capacitor/assets/node_modules/tar": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+ "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/tar/node_modules/minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/tslib": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/@capacitor/assets/node_modules/xml2js": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
+ "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/@capacitor/assets/node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/@capacitor/camera": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/@capacitor/camera/-/camera-8.2.0.tgz",
+ "integrity": "sha512-hYfrT6xpL936qoEkIpJzSnb0fQCaTkOux1cXzGBfH8QLOGqr6gSLiWZlZz/fqMPmMKJMNRBqlTQkj5fuMhVZog==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@capacitor/core": ">=8.0.0"
+ }
+ },
"node_modules/@capacitor/cli": {
"version": "7.6.7",
"resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-7.6.7.tgz",
@@ -585,12 +1014,30 @@
"@capacitor/core": ">=8.0.0"
}
},
+ "node_modules/@capacitor/local-notifications": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/@capacitor/local-notifications/-/local-notifications-8.2.0.tgz",
+ "integrity": "sha512-fvLY0w2w4MiX+DD4+Wv4DOwOLdzKZsMDwAcRv/Juudd+QbKbn69s6cM3xVqPwAiDqfnqsY4/S8xtQD6M73wY2A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@capacitor/core": ">=8.0.0"
+ }
+ },
"node_modules/@capacitor/synapse": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@capacitor/synapse/-/synapse-1.0.4.tgz",
"integrity": "sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==",
"license": "ISC"
},
+ "node_modules/@codetrix-studio/capacitor-google-auth": {
+ "version": "3.4.0-rc.4",
+ "resolved": "https://registry.npmjs.org/@codetrix-studio/capacitor-google-auth/-/capacitor-google-auth-3.4.0-rc.4.tgz",
+ "integrity": "sha512-d548/xKrbMHHbzMYSWnlgZCLZYo2zzY7Onrh3x8ujojrb7atkNK68I6su5WgmaBt4E+R4gxBsWams4554aOFjA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@capacitor/core": "^6.0.0"
+ }
+ },
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@@ -673,7 +1120,6 @@
"os": [
"aix"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -691,7 +1137,6 @@
"os": [
"android"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -709,7 +1154,6 @@
"os": [
"android"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -727,7 +1171,6 @@
"os": [
"android"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -745,7 +1188,6 @@
"os": [
"darwin"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -763,7 +1205,6 @@
"os": [
"darwin"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -781,7 +1222,6 @@
"os": [
"freebsd"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -799,7 +1239,6 @@
"os": [
"freebsd"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -817,7 +1256,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -835,7 +1273,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -853,7 +1290,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -871,7 +1307,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -889,7 +1324,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -907,7 +1341,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -925,7 +1358,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -943,7 +1375,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -961,7 +1392,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -979,7 +1409,6 @@
"os": [
"netbsd"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -997,7 +1426,6 @@
"os": [
"netbsd"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1015,7 +1443,6 @@
"os": [
"openbsd"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1033,7 +1460,6 @@
"os": [
"openbsd"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1051,7 +1477,6 @@
"os": [
"openharmony"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1069,7 +1494,6 @@
"os": [
"sunos"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1087,7 +1511,6 @@
"os": [
"win32"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1105,7 +1528,6 @@
"os": [
"win32"
],
- "peer": true,
"engines": {
"node": ">=18"
}
@@ -1123,11 +1545,20 @@
"os": [
"win32"
],
- "peer": true,
"engines": {
"node": ">=18"
}
},
+ "node_modules/@hutson/parse-repository-url": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz",
+ "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@img/colour": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
@@ -2629,6 +3060,17 @@
"url": "https://github.com/sponsors/Boshen"
}
},
+ "node_modules/@prettier/plugin-xml": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz",
+ "integrity": "sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@xml-tools/parser": "^1.0.11",
+ "prettier": ">=2.4.0"
+ }
+ },
"node_modules/@react-leaflet/core": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
@@ -3263,6 +3705,175 @@
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
"license": "MIT"
},
+ "node_modules/@trapezedev/gradle-parse": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@trapezedev/gradle-parse/-/gradle-parse-7.1.3.tgz",
+ "integrity": "sha512-WQVF5pEJ5o/mUyvfGTG9nBKx9Te/ilKM3r2IT69GlbaooItT5ao7RyF1MUTBNjHLPk/xpGUY3c6PyVnjDlz0Vw==",
+ "dev": true,
+ "license": "SEE LICENSE"
+ },
+ "node_modules/@trapezedev/project": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/@trapezedev/project/-/project-7.1.4.tgz",
+ "integrity": "sha512-b5rszBgT5XiRp/m4V2S2Ara2fdFXhPiduxhvCIVTSHq51PgLBjiTEStL6NbUz3V0K5bebF971O+SLRtyBxfCNA==",
+ "dev": true,
+ "license": "SEE LICENSE",
+ "dependencies": {
+ "@ionic/utils-fs": "^3.1.5",
+ "@ionic/utils-subprocess": "^2.1.8",
+ "@prettier/plugin-xml": "^2.2.0",
+ "@trapezedev/gradle-parse": "7.1.3",
+ "@xmldom/xmldom": "^0.9.9",
+ "conventional-changelog": "^3.1.4",
+ "cross-spawn": "^7.0.3",
+ "diff": "^5.1.0",
+ "env-paths": "^3.0.0",
+ "gradle-to-js": "^2.0.0",
+ "ini": "^2.0.0",
+ "kleur": "^4.1.5",
+ "lodash": "^4.17.21",
+ "plist": "^3.0.4",
+ "prettier": "^2.7.1",
+ "prompts": "^2.4.2",
+ "replace": "^1.1.0",
+ "tempy": "^3.1.0",
+ "tmp": "^0.2.1",
+ "ts-node": "^10.2.1",
+ "xcode": "^3.0.1",
+ "xml-js": "^1.6.11",
+ "xpath": "^0.0.32",
+ "yargs": "^17.2.1"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/@ionic/utils-process": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.11.tgz",
+ "integrity": "sha512-Uavxn+x8j3rDlZEk1X7YnaN6wCgbCwYQOeIjv/m94i1dzslqWhqIHEqxEyeE8HsT5Negboagg7GtQiABy+BLbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ionic/utils-object": "2.1.6",
+ "@ionic/utils-terminal": "2.3.4",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "tree-kill": "^1.2.2",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/@ionic/utils-stream": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.6.tgz",
+ "integrity": "sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/@ionic/utils-subprocess": {
+ "version": "2.1.14",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.14.tgz",
+ "integrity": "sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ionic/utils-array": "2.1.6",
+ "@ionic/utils-fs": "3.1.7",
+ "@ionic/utils-process": "2.1.11",
+ "@ionic/utils-stream": "3.1.6",
+ "@ionic/utils-terminal": "2.3.4",
+ "cross-spawn": "^7.0.3",
+ "debug": "^4.0.0",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/@ionic/utils-terminal": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz",
+ "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/slice-ansi": "^4.0.0",
+ "debug": "^4.0.0",
+ "signal-exit": "^3.0.3",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "tslib": "^2.0.1",
+ "untildify": "^4.0.0",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/diff": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz",
+ "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/env-paths": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
+ "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/prettier": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/@trapezedev/project/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/@tsconfig/node10": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
@@ -3393,6 +4004,13 @@
"@types/geojson": "*"
}
},
+ "node_modules/@types/minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
@@ -3408,6 +4026,13 @@
"undici-types": ">=7.24.0 <7.24.7"
}
},
+ "node_modules/@types/normalize-package-data": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
+ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/pako": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
@@ -3679,6 +4304,16 @@
"@xtuc/long": "4.2.2"
}
},
+ "node_modules/@xml-tools/parser": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz",
+ "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "chevrotain": "7.1.1"
+ }
+ },
"node_modules/@xmldom/xmldom": {
"version": "0.9.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz",
@@ -3754,6 +4389,13 @@
"node": ">=0.4.0"
}
},
+ "node_modules/add-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz",
+ "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/ajv": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
@@ -3866,6 +4508,13 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/array-ify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
+ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/array-timsort": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz",
@@ -3873,6 +4522,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@@ -3939,6 +4598,119 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/bare-events": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz",
+ "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "bare-abort-controller": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-fs": {
+ "version": "4.7.2",
+ "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz",
+ "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.5.4",
+ "bare-path": "^3.0.0",
+ "bare-stream": "^2.6.4",
+ "bare-url": "^2.2.2",
+ "fast-fifo": "^1.3.2"
+ },
+ "engines": {
+ "bare": ">=1.16.0"
+ },
+ "peerDependencies": {
+ "bare-buffer": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-buffer": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-os": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz",
+ "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "bare": ">=1.14.0"
+ }
+ },
+ "node_modules/bare-path": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz",
+ "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-os": "^3.0.1"
+ }
+ },
+ "node_modules/bare-stream": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.3.tgz",
+ "integrity": "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.8.1",
+ "streamx": "^2.25.0",
+ "teex": "^1.0.1"
+ },
+ "peerDependencies": {
+ "bare-abort-controller": "*",
+ "bare-buffer": "*",
+ "bare-events": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ },
+ "bare-buffer": {
+ "optional": true
+ },
+ "bare-events": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-stream/node_modules/b4a": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
+ "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-url": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz",
+ "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-path": "^3.0.0"
+ }
+ },
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
@@ -4063,6 +4835,23 @@
"url": "https://opencollective.com/express"
}
},
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/bplist-creator": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
+ "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "stream-buffers": "2.2.x"
+ }
+ },
"node_modules/bplist-parser": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz",
@@ -4311,6 +5100,34 @@
"node": ">=6"
}
},
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-keys": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+ "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "camelcase": "^5.3.1",
+ "map-obj": "^4.0.0",
+ "quick-lru": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001799",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
@@ -4389,6 +5206,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/chevrotain": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz",
+ "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "regexp-to-ast": "0.5.0"
+ }
+ },
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -4510,6 +5337,20 @@
"node": ">=0.10.0"
}
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -4528,6 +5369,17 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -4552,6 +5404,17 @@
"node": ">= 6"
}
},
+ "node_modules/compare-func": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz",
+ "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-ify": "^1.0.0",
+ "dot-prop": "^5.1.0"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -4624,6 +5487,273 @@
"node": ">= 0.6"
}
},
+ "node_modules/conventional-changelog": {
+ "version": "3.1.25",
+ "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.25.tgz",
+ "integrity": "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "conventional-changelog-angular": "^5.0.12",
+ "conventional-changelog-atom": "^2.0.8",
+ "conventional-changelog-codemirror": "^2.0.8",
+ "conventional-changelog-conventionalcommits": "^4.5.0",
+ "conventional-changelog-core": "^4.2.1",
+ "conventional-changelog-ember": "^2.0.9",
+ "conventional-changelog-eslint": "^3.0.9",
+ "conventional-changelog-express": "^2.0.6",
+ "conventional-changelog-jquery": "^3.0.11",
+ "conventional-changelog-jshint": "^2.0.9",
+ "conventional-changelog-preset-loader": "^2.3.4"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-angular": {
+ "version": "5.0.13",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz",
+ "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "compare-func": "^2.0.0",
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-atom": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz",
+ "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==",
+ "deprecated": "This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-codemirror": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz",
+ "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==",
+ "deprecated": "This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-conventionalcommits": {
+ "version": "4.6.3",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz",
+ "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "compare-func": "^2.0.0",
+ "lodash": "^4.17.15",
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-core": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz",
+ "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==",
+ "deprecated": "Deprecated and no longer maintained. Please use conventional-changelog instead.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "add-stream": "^1.0.0",
+ "conventional-changelog-writer": "^5.0.0",
+ "conventional-commits-parser": "^3.2.0",
+ "dateformat": "^3.0.0",
+ "get-pkg-repo": "^4.0.0",
+ "git-raw-commits": "^2.0.8",
+ "git-remote-origin-url": "^2.0.0",
+ "git-semver-tags": "^4.1.1",
+ "lodash": "^4.17.15",
+ "normalize-package-data": "^3.0.0",
+ "q": "^1.5.1",
+ "read-pkg": "^3.0.0",
+ "read-pkg-up": "^3.0.0",
+ "through2": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-ember": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz",
+ "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==",
+ "deprecated": "This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-eslint": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz",
+ "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==",
+ "deprecated": "This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-express": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz",
+ "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==",
+ "deprecated": "This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-jquery": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz",
+ "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==",
+ "deprecated": "This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-jshint": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz",
+ "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==",
+ "deprecated": "This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "compare-func": "^2.0.0",
+ "q": "^1.5.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-preset-loader": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz",
+ "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-writer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz",
+ "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "conventional-commits-filter": "^2.0.7",
+ "dateformat": "^3.0.0",
+ "handlebars": "^4.7.7",
+ "json-stringify-safe": "^5.0.1",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "semver": "^6.0.0",
+ "split": "^1.0.0",
+ "through2": "^4.0.0"
+ },
+ "bin": {
+ "conventional-changelog-writer": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-changelog-writer/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/conventional-commits-filter": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz",
+ "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash.ismatch": "^4.4.0",
+ "modify-values": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-commits-parser": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz",
+ "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-text-path": "^1.0.1",
+ "JSONStream": "^1.0.4",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "split2": "^3.0.0",
+ "through2": "^4.0.0"
+ },
+ "bin": {
+ "conventional-commits-parser": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/conventional-commits-parser/node_modules/split2": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
+ "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "readable-stream": "^3.0.0"
+ }
+ },
"node_modules/cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
@@ -4654,6 +5784,13 @@
"url": "https://opencollective.com/core-js"
}
},
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
@@ -4719,6 +5856,35 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-random-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz",
+ "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/crypto-random-string/node_modules/type-fest": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
+ "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
@@ -4729,6 +5895,36 @@
"utrie": "^1.0.2"
}
},
+ "node_modules/css-select": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+ "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.0.1",
+ "domhandler": "^4.3.1",
+ "domutils": "^2.8.0",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -4736,6 +5932,16 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/dargs": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
+ "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
@@ -4753,6 +5959,16 @@
"url": "https://opencollective.com/date-fns"
}
},
+ "node_modules/dateformat": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
+ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -4770,6 +5986,59 @@
}
}
},
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decamelize-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
+ "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/decamelize-keys/node_modules/map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/deep-equal": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
@@ -4790,6 +6059,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -4884,6 +6163,50 @@
"node": ">=0.3.1"
}
},
+ "node_modules/dom-serializer": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.0",
+ "entities": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
"node_modules/dompurify": {
"version": "3.4.11",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz",
@@ -4894,6 +6217,34 @@
"@types/trusted-types": "^2.0.7"
}
},
+ "node_modules/domutils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/dotenv": {
"version": "17.4.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
@@ -5008,10 +6359,20 @@
"node": ">= 0.8"
}
},
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/engine.io": {
- "version": "6.6.8",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz",
- "integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==",
+ "version": "6.6.9",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz",
+ "integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
@@ -5023,7 +6384,7 @@
"cors": "~2.8.5",
"debug": "~4.4.1",
"engine.io-parser": "~5.2.1",
- "ws": "~8.20.1"
+ "ws": "~8.21.0"
},
"engines": {
"node": ">=10.2.0"
@@ -5042,27 +6403,6 @@
"xmlhttprequest-ssl": "~2.1.1"
}
},
- "node_modules/engine.io-client/node_modules/ws": {
- "version": "8.21.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
- "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
@@ -5086,6 +6426,16 @@
"node": ">=10.13.0"
}
},
+ "node_modules/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -5200,6 +6550,16 @@
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -5286,12 +6646,32 @@
"node": ">=0.8.x"
}
},
+ "node_modules/events-universal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
+ "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.7.0"
+ }
+ },
"node_modules/exifr": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz",
"integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==",
"license": "MIT"
},
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "dev": true,
+ "license": "(MIT OR WTFPL)",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/express": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
@@ -5392,6 +6772,13 @@
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==",
"license": "Apache-2.0"
},
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -5505,6 +6892,19 @@
"url": "https://opencollective.com/express"
}
},
+ "node_modules/find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/fork-ts-checker-webpack-plugin": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.1.0.tgz",
@@ -5569,6 +6969,13 @@
"resolved": "frontend",
"link": true
},
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
@@ -5584,6 +6991,32 @@
"node": ">=12"
}
},
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs-minipass/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/fs-monkey": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz",
@@ -5591,11 +7024,17 @@
"dev": true,
"license": "Unlicense"
},
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -5667,6 +7106,110 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-pkg-repo": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz",
+ "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@hutson/parse-repository-url": "^3.0.0",
+ "hosted-git-info": "^4.0.0",
+ "through2": "^2.0.0",
+ "yargs": "^16.2.0"
+ },
+ "bin": {
+ "get-pkg-repo": "src/cli.js"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/get-pkg-repo/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/yargs": {
+ "version": "16.2.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz",
+ "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/get-pkg-repo/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
@@ -5680,6 +7223,103 @@
"node": ">= 0.4"
}
},
+ "node_modules/git-raw-commits": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz",
+ "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==",
+ "deprecated": "Deprecated and no longer maintained. Use @conventional-changelog/git-client instead.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dargs": "^7.0.0",
+ "lodash": "^4.17.15",
+ "meow": "^8.0.0",
+ "split2": "^3.0.0",
+ "through2": "^4.0.0"
+ },
+ "bin": {
+ "git-raw-commits": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/git-raw-commits/node_modules/split2": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
+ "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "readable-stream": "^3.0.0"
+ }
+ },
+ "node_modules/git-remote-origin-url": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz",
+ "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "gitconfiglocal": "^1.0.0",
+ "pify": "^2.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/git-semver-tags": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz",
+ "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==",
+ "deprecated": "Deprecated and no longer maintained. Use @conventional-changelog/git-client instead.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "meow": "^8.0.0",
+ "semver": "^6.0.0"
+ },
+ "bin": {
+ "git-semver-tags": "cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/git-semver-tags/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/gitconfiglocal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz",
+ "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==",
+ "dev": true,
+ "license": "BSD",
+ "dependencies": {
+ "ini": "^1.3.2"
+ }
+ },
+ "node_modules/gitconfiglocal/node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
@@ -5758,6 +7398,61 @@
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
+ "node_modules/gradle-to-js": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/gradle-to-js/-/gradle-to-js-2.0.1.tgz",
+ "integrity": "sha512-is3hDn9zb8XXnjbEeAEIqxTpLHUiGBqjegLmXPuyMBfKAggpadWFku4/AP8iYAGBX6qR9/5UIUIp47V0XI3aMw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "lodash.merge": "^4.6.2"
+ },
+ "bin": {
+ "gradle-to-js": "cli.js"
+ }
+ },
+ "node_modules/handlebars": {
+ "version": "4.7.9",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
+ "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.2",
+ "source-map": "^0.6.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
+ },
+ "engines": {
+ "node": ">=0.4.7"
+ },
+ "optionalDependencies": {
+ "uglify-js": "^3.1.4"
+ }
+ },
+ "node_modules/handlebars/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/hard-rejection": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+ "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -5831,6 +7526,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
"node_modules/heic-convert": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/heic-convert/-/heic-convert-2.1.0.tgz",
@@ -5863,6 +7568,32 @@
"integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==",
"license": "MIT"
},
+ "node_modules/hosted-git-info": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+ "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/hosted-git-info/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
@@ -5950,6 +7681,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -6003,6 +7744,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/is-core-module": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-date-object": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
@@ -6053,6 +7810,26 @@
"node": ">=8"
}
},
+ "node_modules/is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
@@ -6077,6 +7854,32 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-text-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz",
+ "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "text-extensions": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
@@ -6102,6 +7905,13 @@
"node": ">=8"
}
},
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -6177,6 +7987,13 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -6191,6 +8008,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -6223,6 +8047,33 @@
"graceful-fs": "^4.1.6"
}
},
+ "node_modules/jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+ "dev": true,
+ "engines": [
+ "node >= 0.2.0"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/JSONStream": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+ "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+ "dev": true,
+ "license": "(MIT OR Apache-2.0)",
+ "dependencies": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ },
+ "bin": {
+ "JSONStream": "bin.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/jsonwebtoken": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
@@ -6301,6 +8152,16 @@
"@keyv/serialize": "^1.1.1"
}
},
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/kleur": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
@@ -6621,6 +8482,46 @@
"node": ">=13.2.0"
}
},
+ "node_modules/load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/load-json-file/node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/load-json-file/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/loader-runner": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz",
@@ -6635,6 +8536,20 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/lodash": {
"version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
@@ -6678,6 +8593,13 @@
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
+ "node_modules/lodash.ismatch": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
+ "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
@@ -6696,6 +8618,13 @@
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@@ -6766,6 +8695,19 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/map-obj": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -6797,6 +8739,202 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/meow": {
+ "version": "8.1.2",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz",
+ "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/minimist": "^1.2.0",
+ "camelcase-keys": "^6.2.2",
+ "decamelize-keys": "^1.1.0",
+ "hard-rejection": "^2.1.0",
+ "minimist-options": "4.1.0",
+ "normalize-package-data": "^3.0.0",
+ "read-pkg-up": "^7.0.1",
+ "redent": "^3.0.0",
+ "trim-newlines": "^3.0.0",
+ "type-fest": "^0.18.0",
+ "yargs-parser": "^20.2.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/meow/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/meow/node_modules/hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/meow/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/meow/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/meow/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/meow/node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/meow/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/meow/node_modules/read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/meow/node_modules/read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/meow/node_modules/semver": {
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/meow/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/merge-descriptors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
@@ -6856,6 +8994,29 @@
"node": ">=6"
}
},
+ "node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
@@ -6879,6 +9040,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/minimist-options": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+ "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0",
+ "kind-of": "^6.0.3"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
@@ -6900,6 +9076,36 @@
"node": ">= 18"
}
},
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/modify-values": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz",
+ "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -6976,6 +9182,13 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/napi-build-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
+ "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/native-run": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.3.tgz",
@@ -7017,6 +9230,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/node-abi": {
+ "version": "3.92.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz",
+ "integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/node-abort-controller": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz",
@@ -7043,6 +9269,27 @@
"lodash": "^4.17.21"
}
},
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
"node_modules/node-gyp-build": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
@@ -7054,6 +9301,17 @@
"node-gyp-build-test": "build-test.js"
}
},
+ "node_modules/node-html-parser": {
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.4.2.tgz",
+ "integrity": "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "css-select": "^4.2.1",
+ "he": "1.2.0"
+ }
+ },
"node_modules/node-releases": {
"version": "2.0.47",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz",
@@ -7073,6 +9331,35 @@
"node": ">=6.0.0"
}
},
+ "node_modules/normalize-package-data": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+ "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "hosted-git-info": "^4.0.1",
+ "is-core-module": "^2.5.0",
+ "semver": "^7.3.4",
+ "validate-npm-package-license": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -7206,6 +9493,42 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@@ -7301,6 +9624,16 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -7310,6 +9643,13 @@
"node": ">=8"
}
},
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/path-scurry": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
@@ -7482,6 +9822,16 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/plist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz",
@@ -7581,6 +9931,94 @@
"node": ">=0.10.0"
}
},
+ "node_modules/prebuild-install": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
+ "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
+ "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^2.0.0",
+ "node-abi": "^3.3.0",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^4.0.0",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/prebuild-install/node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/prebuild-install/node_modules/tar-fs": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+ "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/prebuild-install/node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.8.5",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.5.tgz",
+ "integrity": "sha512-zxcTTCedNGJM4R8sj/Cq/F0W/c4iE0afWBcBwMTRtw4WHYP9TWkYjdiH3npPRUYsXQCPR0hTU9yjovOu+E6EQA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/promise-coalesce": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/promise-coalesce/-/promise-coalesce-1.5.0.tgz",
@@ -7625,6 +10063,17 @@
"node": ">= 0.10"
}
},
+ "node_modules/pump": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
+ "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -7635,6 +10084,18 @@
"node": ">=6"
}
},
+ "node_modules/q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
+ "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6.0",
+ "teleport": ">=0.2.0"
+ }
+ },
"node_modules/qs": {
"version": "6.15.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
@@ -7650,6 +10111,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/quick-lru": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/quill": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
@@ -7727,6 +10198,29 @@
"node": ">= 0.10"
}
},
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dev": true,
+ "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/rc/node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@@ -7796,6 +10290,88 @@
"react-dom": "^16 || ^17 || ^18"
}
},
+ "node_modules/read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/read-pkg-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/read-pkg/node_modules/hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/read-pkg/node_modules/normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "node_modules/read-pkg/node_modules/path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/read-pkg/node_modules/pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/read-pkg/node_modules/semver": {
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -7824,6 +10400,20 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/redis": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/redis/-/redis-6.0.0.tgz",
@@ -7912,6 +10502,12 @@
"@redis/client": "^6.0.0"
}
},
+ "node_modules/reflect-metadata": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
+ "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
+ "license": "Apache-2.0"
+ },
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
@@ -7919,6 +10515,13 @@
"license": "MIT",
"optional": true
},
+ "node_modules/regexp-to-ast": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz",
+ "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/regexp.prototype.flags": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
@@ -7939,6 +10542,289 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/replace": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz",
+ "integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "2.4.2",
+ "minimatch": "3.0.5",
+ "yargs": "^15.3.1"
+ },
+ "bin": {
+ "replace": "bin/replace.js",
+ "search": "bin/search.js"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/replace/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/replace/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/replace/node_modules/cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "node_modules/replace/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/replace/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/replace/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/replace/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/replace/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/replace/node_modules/minimatch": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz",
+ "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/replace/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/replace/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/replace/node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/replace/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/replace/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/replace/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/replace/node_modules/wrap-ansi/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/replace/node_modules/wrap-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/replace/node_modules/wrap-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/replace/node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/replace/node_modules/yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/replace/node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -7959,6 +10845,35 @@
"node": ">=0.10.0"
}
},
+ "node_modules/require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/resolve": {
+ "version": "1.22.12",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
+ "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -8245,6 +11160,13 @@
"url": "https://opencollective.com/express"
}
},
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -8446,6 +11368,95 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/simple-get": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decompress-response": "^6.0.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "node_modules/simple-plist": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz",
+ "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bplist-creator": "0.1.0",
+ "bplist-parser": "0.3.1",
+ "plist": "^3.0.5"
+ }
+ },
+ "node_modules/simple-plist/node_modules/bplist-parser": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz",
+ "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "big-integer": "1.6.x"
+ },
+ "engines": {
+ "node": ">= 5.10.0"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -8488,13 +11499,13 @@
}
},
"node_modules/socket.io-adapter": {
- "version": "2.5.7",
- "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz",
- "integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==",
+ "version": "2.5.8",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz",
+ "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==",
"license": "MIT",
"dependencies": {
"debug": "~4.4.1",
- "ws": "~8.20.1"
+ "ws": "~8.21.0"
}
},
"node_modules/socket.io-client": {
@@ -8572,6 +11583,55 @@
"integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
"dev": true
},
+ "node_modules/spdx-correct": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+ "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+ "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+ "dev": true,
+ "license": "CC-BY-3.0"
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.23",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz",
+ "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "through": "2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
@@ -8600,6 +11660,16 @@
"node": ">= 0.8"
}
},
+ "node_modules/stream-buffers": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
+ "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==",
+ "dev": true,
+ "license": "Unlicense",
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -8608,6 +11678,18 @@
"node": ">=10.0.0"
}
},
+ "node_modules/streamx": {
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz",
+ "integrity": "sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "events-universal": "^1.0.0",
+ "fast-fifo": "^1.3.2",
+ "text-decoder": "^1.1.0"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -8653,6 +11735,29 @@
"node": ">=4"
}
},
+ "node_modules/strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "min-indent": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/strtok3": {
"version": "10.3.5",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz",
@@ -8685,6 +11790,19 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
@@ -8742,6 +11860,49 @@
"node": ">=18"
}
},
+ "node_modules/tar-fs": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz",
+ "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0",
+ "tar-stream": "^3.1.5"
+ },
+ "optionalDependencies": {
+ "bare-fs": "^4.0.1",
+ "bare-path": "^3.0.0"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz",
+ "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "b4a": "^1.6.4",
+ "bare-fs": "^4.5.5",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ },
+ "node_modules/tar-stream/node_modules/b4a": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
+ "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
"node_modules/tar/node_modules/yallist": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
@@ -8751,6 +11912,58 @@
"node": ">=18"
}
},
+ "node_modules/teex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
+ "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "streamx": "^2.12.5"
+ }
+ },
+ "node_modules/temp-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz",
+ "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ }
+ },
+ "node_modules/tempy": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.2.0.tgz",
+ "integrity": "sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-stream": "^3.0.0",
+ "temp-dir": "^3.0.0",
+ "type-fest": "^2.12.2",
+ "unique-string": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/tempy/node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/terser": {
"version": "5.48.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz",
@@ -8876,6 +12089,41 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/text-decoder": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
+ "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.6.4"
+ }
+ },
+ "node_modules/text-decoder/node_modules/b4a": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
+ "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/text-extensions": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz",
+ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
@@ -8886,6 +12134,13 @@
"utrie": "^1.0.2"
}
},
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/through2": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
@@ -8912,6 +12167,16 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
+ "node_modules/tmp": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
+ "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -8939,6 +12204,13 @@
"url": "https://github.com/sponsors/Borewit"
}
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
@@ -8948,6 +12220,16 @@
"tree-kill": "cli.js"
}
},
+ "node_modules/trim-newlines": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
@@ -9048,6 +12330,32 @@
"fsevents": "~2.3.3"
}
},
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+ "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/type-is": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz",
@@ -9115,6 +12423,20 @@
"node": ">=14.17"
}
},
+ "node_modules/uglify-js": {
+ "version": "3.19.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
+ "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "optional": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/uid": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz",
@@ -9145,6 +12467,22 @@
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
"license": "MIT"
},
+ "node_modules/unique-string": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz",
+ "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "crypto-random-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
@@ -9238,6 +12576,17 @@
"base64-arraybuffer": "^1.0.2"
}
},
+ "node_modules/uuid": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
+ "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
+ "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
@@ -9245,6 +12594,17 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -9355,6 +12715,13 @@
"defaults": "^1.0.3"
}
},
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
"node_modules/webpack": {
"version": "5.106.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz",
@@ -9461,6 +12828,17 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -9476,6 +12854,20 @@
"node": ">= 8"
}
},
+ "node_modules/which-module": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -9500,9 +12892,9 @@
"license": "ISC"
},
"node_modules/ws": {
- "version": "8.20.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
- "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -9520,6 +12912,43 @@
}
}
},
+ "node_modules/xcode": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz",
+ "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "simple-plist": "^1.1.0",
+ "uuid": "^7.0.3"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/xml-js": {
+ "version": "1.6.11",
+ "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
+ "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sax": "^1.2.4"
+ },
+ "bin": {
+ "xml-js": "bin/cli.js"
+ }
+ },
+ "node_modules/xml-js/node_modules/sax": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
+ "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=11.0.0"
+ }
+ },
"node_modules/xml2js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
@@ -9559,6 +12988,16 @@
"node": ">=0.4.0"
}
},
+ "node_modules/xpath": {
+ "version": "0.0.32",
+ "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz",
+ "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
diff --git a/task.md b/task.md
new file mode 100644
index 0000000..e820c74
--- /dev/null
+++ b/task.md
@@ -0,0 +1,46 @@
+# Nhiệm vụ: Sửa giao diện Bong bóng Tour & Kết nối Thành viên
+
+- [x] [Database] Thêm model `UserConnection` và `DirectMessage` vào schema.prisma và chạy db:migrate
+- [x] [Backend] Tạo các API quản lý kết nối (`connections`) và tin nhắn (`messages`) cùng WebSocket Gateway
+- [x] [Frontend] Sửa luồng redirect sau khi đăng nhập/đăng ký bằng Google trong App.tsx
+- [x] [Frontend] Sửa vị trí tâm neo bong bóng Tour (iconSize & iconAnchor) trong ExploreMap.tsx
+- [x] [Frontend] Thêm màu viền (xanh, đỏ, trắng) và tooltip phân loại Tour trên bản đồ khám phá
+- [x] [Frontend] Chặn click trái đối với tour viền xanh; cài đặt touchstart/contextmenu để xin join bằng nhấn giữ/click phải
+- [x] [Frontend] Xây dựng trang Dashboard thành viên (`MemberDashboard.tsx`) tích hợp chat box, quản lý kết nối bạn bè/gia đình, quản lý tour và ảnh cá nhân
+
+## Giai đoạn 2: Sửa đổi giao diện Dashboard Thành viên (Desktop & Mobile)
+- [x] [Frontend] Cập nhật giao diện MyPhotosPage.tsx thành Dark Slate theme để đồng bộ với dashboard
+- [x] [Frontend] Tích hợp trực tiếp MyPhotosPage vào tab Thư viện ảnh trong MemberDashboard.tsx
+- [x] [Frontend] Sửa giao diện Desktop của MemberDashboard.tsx: căn giữa h-[90vh], chỉnh màu thẻ tour, và sửa đè viền Mạng lưới kết nối
+- [x] [Frontend] Sửa giao diện Mobile của MemberDashboard.tsx: thiết lập hiển thị fullscreen menu các nút, và quay lại menu từ các trang chi tiết/chat
+- [x] Xác minh toàn bộ tính năng và lỗi hiển thị trên cả desktop và điện thoại di động
+
+## Giai đoạn 3: Realtime Notification qua WebSockets
+- [x] [Backend] Thêm notifyConnectionAccepted và notifyJoinRequestAccepted vào CommentGateway trong main.ts
+- [x] [Backend] Inject CommentGateway và trigger notifyConnectionAccepted trong ConnectionController
+- [x] [Backend] Inject CommentGateway và trigger notifyJoinRequestAccepted trong TourController
+- [x] [Frontend] Thêm event listeners (connectionAccepted, joinRequestAccepted) vào socket hook trong MemberDashboard.tsx
+- [x] Xác minh các sự kiện thông báo thời gian thực trên giao diện người dùng
+
+## Giai đoạn 4: Notification Badges & System Push Notifications (Mobile/Desktop)
+- [x] [Frontend] Khởi tạo yêu cầu quyền Notification hệ thống khi mount và tạo helper showSystemNotification
+- [x] [Frontend] Khai báo các state unreadChatSenders và unreadTourSenders cùng helper isMemberOfMyTours
+- [x] [Frontend] Cập nhật event listener messageReceived để kích hoạt push notification và set các state chưa đọc
+- [x] [Frontend] Hiển thị Badge thông báo trên các tab/menu button và danh sách chat liên hệ
+- [x] [Frontend] Xử lý xóa trạng thái chưa đọc khi chọn chat user hoặc click tab Hành trình của tôi
+- [x] Xác minh hiển thị Badge và thông báo đẩy hệ thống thành công trên cả desktop/mobile
+
+## Giai đoạn 5: Trò chuyện Nhóm Hành trình & Đính kèm (Ảnh nén 2K + Vị trí GPS)
+- [x] [Database] Cập nhật schema.prisma (thêm TourMessage và các trường DirectMessage), chạy db migration
+- [x] [Backend] Thêm UploadController, cập nhật DirectMessageController và tạo TourMessageController trong main.ts
+- [x] [Frontend] Viết component TourChat.tsx (nén canvas 2K, tải ảnh, lấy vị trí GPS)
+- [x] [Frontend] Tích hợp tab Trò chuyện và sự kiện socket vào TourDetailPage.tsx
+- [x] [Frontend] Nâng cấp giao diện chat trong MemberDashboard.tsx (nén canvas 2K, tải ảnh, GPS, và badge tour chat)
+- [x] Xác minh biên dịch TypeScript và chạy các kịch bản kiểm thử trò chuyện trực tiếp/nhóm thành công
+
+## Giai đoạn 6: Nhắc tên (@Mention) trong Chat & Tắt thông báo
+- [x] [Frontend] Sửa lỗi hiển thị bong bóng tour trên bản đồ bằng cách quét tất cả chặng (ExploreMap.tsx)
+- [x] [Backend] Cập nhật API gửi tin nhắn nhóm tour để nhận taggedUserIds và gửi socket notification riêng (main.ts)
+- [x] [Frontend] Thêm chức năng tag @ thành viên trong component TourChat.tsx
+- [x] [Frontend] Thêm nút Bật/Tắt thông báo đẩy & logic Mute trong MemberDashboard.tsx
+- [x] Xác minh biên dịch TypeScript và chạy các kịch bản kiểm thử tag & mute thành công
diff --git a/ui_implementation_plan.md b/ui_implementation_plan.md
new file mode 100644
index 0000000..5a17822
--- /dev/null
+++ b/ui_implementation_plan.md
@@ -0,0 +1,185 @@
+# Kế hoạch: Tái thiết kế giao diện xem ảnh và bình luận trên Mobile (PublicPhotoModal)
+
+Thiết kế lại giao diện mobile của modal xem ảnh công khai để trải nghiệm cuộn trang tự nhiên hơn, tương tự như Instagram/Twitter — ảnh chiếm toàn bộ chiều rộng màn hình từ trên xuống, thông tin người đăng và các nút được bố cục rõ ràng, sau đó cuộn xuống xem bình luận một cách liền mạch.
+
+---
+
+## Phân tích hiện trạng
+
+Cấu trúc hiện tại của modal trên mobile (`flex flex-col`):
+1. **Container (90vh, overflow-hidden)** — toàn bộ nội dung bị "kẹt" trong 90vh
+2. Phần ảnh (`h-[45vh]`) — cố định, không thể co giãn
+3. Phần "Mobile Uploader" strip — cố định (`shrink-0`)
+4. Phần comment panel (`flex-1 min-h-0`) — chỉ phần danh sách comment cuộn bên trong
+
+**Vấn đề**: Ảnh bị giới hạn ở `h-[45vh]`, có padding `p-4` từ container ngoài nên không chạm mép màn hình. Nút like nằm ở góc trên trái (gần nút X), người đăng nằm ở vùng riêng giữa ảnh và comment, không cuộn cùng content.
+
+---
+
+## Thay đổi đề xuất
+
+### [MODIFY] [PublicPhotoModal.tsx](file:///home/locpham/travelplanning/frontend/src/components/PublicPhotoModal.tsx)
+
+#### 1. Outer wrapper — Bỏ padding và căn giữa
+
+**Hiện tại** (line 358):
+```
+
+```
+
+**Thay thành** — trên mobile modal full screen, không padding, không căn giữa. Desktop giữ nguyên layout cũ:
+```
+
+```
+
+#### 2. Container modal — Mobile: full screen cuộn tự nhiên; Desktop: giữ nguyên
+
+**Hiện tại** (line 366):
+```
+
+```
+
+**Thay thành**:
+- Mobile: `fixed inset-0 overflow-y-auto flex flex-col bg-slate-900` — toàn màn hình, cuộn tự nhiên theo trang
+- Desktop: `relative w-full max-w-5xl h-[85vh] overflow-hidden flex flex-row rounded-[32px]`
+
+```
+
+```
+
+#### 3. Nút X — Fixed ở góc trên phải (hiện tại đúng, cần giữ nguyên)
+
+Nút X hiện đang dùng `fixed` — **giữ nguyên**, chỉ điều chỉnh `top` để tính safe-area:
+```
+className="fixed top-[calc(1rem+env(safe-area-inset-top,0px))] right-4 z-50 ..."
+```
+
+#### 4. Phần ảnh (Left Side Photo) — Mobile: full width, không giới hạn chiều cao, aspect ratio tự nhiên
+
+**Hiện tại** (line 377):
+```
+
+```
+
+**Thay thành** — Trên mobile: ảnh full width, chiều cao theo tỷ lệ ảnh (aspect-ratio), không giới hạn, chạm mép trên màn hình (không có padding trên):
+```
+
+```
+
+Với ảnh bên trong:
+```
+
+```
+
+#### 5. Nút Like — Di chuyển từ góc trên trái sang góc dưới phải của vùng ảnh
+
+**Hiện tại**: `absolute top-[...] left-4` — góc trên bên trái.
+
+**Thay thành**: `absolute bottom-4 right-4` — góc dưới bên phải của ảnh, không bị che bởi thanh địa chỉ và không xung đột với nút X:
+```
+className="absolute bottom-4 right-4 z-40 ..."
+```
+
+#### 6. Thông tin người đăng — Di chuyển thành overlay góc trên trái trên ảnh
+
+Hiện tại "Mobile Uploader strip" là một block riêng biệt giữa ảnh và comment (`block md:hidden p-6 ...`).
+
+**Thay thành**: Overlay trực tiếp trên ảnh ở góc **trên bên trái**, nằm trong vùng ảnh, có safe-area padding:
+```html
+
+
+
+
+
+
{photo.uploader?.name || 'Ẩn danh'}
+
+```
+
+#### 7. "Mobile Uploader strip" block — Xóa block cũ
+
+Block `{/* Mobile Only: Uploader details & divider */}` ở lines 597–623 sẽ được **xóa** vì thông tin người đăng đã được hiển thị trực tiếp trên ảnh ở bước 6.
+
+Nếu `isAuthorized && photo.originalUrl` (nút Tải ảnh gốc): sẽ được giữ lại nhưng chuyển vào trong phần metadata/overlay của ảnh hoặc đặt trước phần comments.
+
+#### 8. Phần Comments — Cuộn cùng với nội dung (không bị kẹt trong flex)
+
+Trên mobile, toàn bộ trang cuộn — phần comment không cần `overflow-y-auto` riêng nữa (vì parent đã cuộn):
+
+**Hiện tại** (line 626):
+```
+
+```
+
+**Thay thành**:
+```
+
+```
+
+Danh sách bình luận (line 640):
+```
+
+```
+→ Trên mobile không giới hạn `overflow-y-auto`:
+```
+
+```
+
+#### 9. Comment Input — Sticky ở cuối trang trên mobile
+
+Thay vì nằm cố định cuối flex column, ô nhập bình luận sẽ sticky ở bottom:
+```
+
+```
+
+---
+
+## Tóm tắt layout cuối cùng trên mobile
+
+```
+┌─────────────────────────────────────────────┐ ← màn hình (fixed inset-0)
+│ [X nút đóng] (góc trên phải, fixed/z-50)
+│─────────────────────────────────────────────│
+│ │
+│ [Người đăng] (overlay TL) │
+│ │ ← Vùng ảnh (full width,
+│ ẢNH │ height theo tỷ lệ)
+│ │
+│ [❤ Like + số] │
+│─────────────────────────────────────────────│
+│ 📷 Timeline ảnh (nếu có nhiều ảnh) │ ← Cuộn cùng trang
+│─────────────────────────────────────────────│
+│ Tiêu đề, mô tả, ngày chụp, địa điểm │ ← Info overlay panel
+│─────────────────────────────────────────────│
+│ [Tải ảnh gốc] (nếu là chủ sở hữu) │
+│─────────────────────────────────────────────│
+│ 💬 Comment 1 │ ← Cuộn cùng trang
+│ 💬 Comment 2 │
+│ 💬 Comment 3 │
+│ ... │
+│─────────────────────────────────────────────│
+│ [Viết bình luận...] [▶ Gửi] (sticky bottom)│
+└─────────────────────────────────────────────┘
+```
+
+---
+
+## Verification Plan
+
+### Automated Tests
+- `npm run build -w frontend` — không có lỗi compilation.
+
+### Manual Verification
+1. Mở app trên Chrome mobile (Android) → modal mở full screen, ảnh chạm top, không có padding.
+2. Nút X hiển thị góc trên phải, luôn visible.
+3. Tên người đăng hiển thị overlay góc trên trái, không nhầm với người bình luận.
+4. Nút like hiển thị góc dưới phải của ảnh.
+5. Vuốt lên → ảnh và bình luận cuộn cùng nhau một cách liền mạch.
+6. Ô bình luận sticky ở dưới cùng.
+7. Trên desktop (≥768px) layout 2 cột giữ nguyên hoàn toàn.
+8. Safe area insets hoạt động đúng trên iPhone (notch/Dynamic Island) dùng Safari.
diff --git a/yotrip_system_fix_plan.md b/yotrip_system_fix_plan.md
new file mode 100644
index 0000000..50ce739
--- /dev/null
+++ b/yotrip_system_fix_plan.md
@@ -0,0 +1,171 @@
+# Kế hoạch triển khai: Tính năng nâng cấp & Sửa lỗi hệ thống YoTrip
+
+Bản kế hoạch này phác thảo chi tiết phương án kỹ thuật để thực hiện các tính năng mới và khắc phục các lỗi tồn tại trong dự án theo yêu cầu.
+
+---
+
+## User Review Required
+
+> [!IMPORTANT]
+> - **Cập nhật database schema (Prisma Migrations)**: Chúng ta cần thêm bảng mới `TourNote` và `RecommendedLocation`, đồng thời bổ sung các trường `isDeleted` và `deletedAt` cho bảng `Tour` và `Photo` để phục vụ tính năng Thùng rác (Trash Bin). Việc này yêu cầu chạy prisma migrations (`npx prisma migrate dev`).
+> - **Thay đổi Nginx config**: Cấu hình Nginx trong Docker production cần bổ sung `client_max_body_size 50M;` để hỗ trợ tải ảnh lớn lên proxy trước khi nén trên client, tránh lỗi HTTP 413.
+> - **Cơ chế Hybrid Lưu trữ Ghi chú (Notes)**: Ghi chú sẽ được lưu trữ song song (hybrid) cả ở `localStorage` (để hiển thị tức thời và hoạt động offline) lẫn đồng bộ lên server (để lưu trữ lâu dài và cho phép Admin kiểm duyệt/moderation). Khi mở trang ghi chú, ứng dụng sẽ tải dữ liệu từ cache `localStorage` trước, sau đó fetch dữ liệu mới nhất từ server để đồng bộ và cập nhật lại cache.
+
+---
+
+## Proposed Changes
+
+### 1. Cơ sở dữ liệu (Database Schema)
+
+#### [MODIFY] [schema.prisma](file:///home/locpham/travelplanning/backend/prisma/schema.prisma)
+- **Bảng `Photo` & `Tour`**: Bổ sung hai trường `isDeleted Boolean @default(false)` và `deletedAt DateTime?` để hỗ trợ cơ chế soft-delete (chuyển vào thùng rác).
+- **Bảng `ModerationSetting`**: Thêm trường `trashRetentionDays Int @default(30)` để lưu trữ số ngày lưu trữ trong thùng rác do admin quy định.
+- **Thêm bảng `TourNote`**: Lưu trữ ghi chú của Tour liên kết với `Tour` và `User` sở hữu:
+ ```prisma
+ model TourNote {
+ id String @id @default(uuid())
+ tourId String
+ tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
+ userId String
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+ title String
+ content String @db.Text
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ isDeleted Boolean @default(false)
+ deletedAt DateTime?
+ }
+ ```
+- **Thêm bảng `RecommendedLocation`**: Lưu trữ các địa điểm đề xuất:
+ ```prisma
+ model RecommendedLocation {
+ id String @id @default(uuid())
+ type String // e.g. "RESTAURANT", "HOTEL", "HOMESTAY"
+ name String
+ phone String?
+ email String?
+ address String?
+ latitude Float?
+ longitude Float?
+ description String @db.Text
+ stars Int @default(5) // Số sao đánh giá từ 1 đến 5
+ isApproved Boolean @default(false)
+ createdAt DateTime @default(now())
+ }
+ ```
+
+---
+
+### 2. Backend API (`backend/src/main.ts`)
+
+- **Soft-Delete cho Tours, Photos, và Notes**:
+ - Cập nhật hàm `deleteTour`, `deletePhoto` để chỉ set `isDeleted: true` và `deletedAt: new Date()` thay vì xóa vĩnh viễn.
+ - Cập nhật tất cả các truy vấn tour, ảnh (public & private) để loại trừ các bản ghi có `isDeleted: true`.
+- **TourNote API**:
+ - `GET /api/v1/tours/:tourId/notes`: Lấy danh sách ghi chú của một tour (phải là thành viên tour hoặc admin).
+ - `POST /api/v1/tours/:tourId/notes`: Tạo ghi chú cho tour.
+ - `PUT /api/v1/tours/:tourId/notes/:noteId`: Sửa ghi chú.
+ - `DELETE /api/v1/tours/:tourId/notes/:noteId`: Soft-delete ghi chú của tour.
+- **RecommendedLocation API**:
+ - `GET /api/v1/recommendations`: Lấy danh sách địa điểm đề xuất đã duyệt (`isApproved: true`).
+ - `POST /api/v1/recommendations`: Người dùng gửi đề xuất địa điểm mới.
+ - `GET /api/v1/admin/recommendations`: Admin xem toàn bộ danh sách đề xuất.
+ - `PATCH /api/v1/admin/recommendations/:id/approve`: Admin phê duyệt địa điểm đề xuất.
+ - `DELETE /api/v1/admin/recommendations/:id`: Admin xóa đề xuất.
+- **Admin Trash Bin API**:
+ - `GET /api/v1/admin/trash`: Lấy danh sách các đối tượng trong thùng rác (phân loại Tours, Photos, Notes) kèm thông tin ngày xóa.
+ - `POST /api/v1/admin/trash/restore`: Phục hồi các đối tượng được chọn (`isDeleted: false`).
+ - `POST /api/v1/admin/trash/delete-permanent`: Xóa vĩnh viễn các đối tượng được chọn khỏi ổ đĩa và DB.
+ - `PATCH /api/v1/admin/trash/retention-days`: Cập nhật cấu hình `trashRetentionDays`.
+- **Cronjob dọn dẹp tự động (Background Service)**:
+ - Khởi tạo một task chạy định kỳ (24 giờ một lần) quét qua các bảng `Tour`, `Photo`, `TourNote` có `isDeleted: true` và `deletedAt` đã quá hạn so với cấu hình `trashRetentionDays` để tự động xóa vĩnh viễn bản ghi và tệp vật lý.
+
+---
+
+### 3. Frontend & UI
+
+#### [MODIFY] [nginx.conf](file:///home/locpham/travelplanning/frontend/nginx.conf)
+- Thêm dòng `client_max_body_size 50M;` vào cấu hình block `server` của Nginx để khắc phục triệt để lỗi `413 (Request Entity Too Large)`.
+
+#### [NEW] [image.ts](file:///home/locpham/travelplanning/frontend/src/utils/image.ts)
+- Viết hàm tiện ích nén ảnh trên Client sử dụng Canvas API, giảm kích thước ảnh về chiều dài nhất tối đa **2048px (2K)**, chuyển định dạng sang `image/jpeg` chất lượng `0.85` trước khi tải lên.
+- Áp dụng hàm nén này cho:
+ - Chụp ảnh/Tải ảnh ẩn danh ở [LandingPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/LandingPage.tsx)
+ - Tải ảnh lên trong Tour ở [AddPhotoModal.tsx](file:///home/locpham/travelplanning/frontend/src/components/AddPhotoModal.tsx)
+ - Các vị trí upload ảnh khác.
+
+#### [MODIFY] [LoginModal.tsx](file:///home/locpham/travelplanning/frontend/src/components/LoginModal.tsx)
+- Thêm class CSS `max-h-[90vh] overflow-y-auto` vào container chính của modal để tránh bị che mất nút đăng nhập trên các trình duyệt di động có chiều cao màn hình nhỏ hoặc khi bàn phím ảo hiển thị.
+
+#### [MODIFY] [TourDetailPage.tsx](file:///home/locpham/travelplanning/frontend/src/pages/TourDetailPage.tsx)
+- **Khắc phục lỗi xuất PDF (`oklab` error)**:
+ - Thay vì clone trực tiếp DOM timeline chứa màu oklab phức tạp của Tailwind v4, chúng ta sẽ xây dựng trực tiếp một phần tử HTML `div` đơn giản, dùng cấu trúc bảng hoặc danh sách căn lề cơ bản, sử dụng màu HEX tiêu chuẩn (`#ffffff`, `#3b82f6`, v.v.).
+ - Trước khi gọi `html2pdf().from(element).save()`, tạm thời đặt `.disabled = true` cho tất cả các thẻ `