Merge remote-tracking branch 'refs/remotes/origin/main'

This commit is contained in:
Alexis Leboeuf
2026-01-07 18:07:17 +01:00
13 changed files with 411 additions and 245 deletions

View File

@@ -12,6 +12,7 @@ api.interceptors.request.use((config) => {
if (keycloak?.token) {
// eslint-disable-next-line no-param-reassign
config.headers.Authorization = `Bearer ${keycloak.token}`;
console.log(config.headers.Authorization);
}
return config;
});

View File

@@ -5,9 +5,17 @@ export class User{
id!: number;
nom!: String;
sessions: Session[] = []; //nb: Admin liaison non symétrique /!\
email!: String;
role!: Role;
}
export class Ligne{
id!: number;
nom!: String;
composition!: Athlete[] //les joueurs compososant la ligne
tempsDeJeu!: number; // en minutes
}
export class Admin extends User{
role!: Role;
@@ -37,6 +45,7 @@ export class Session{
athletes!: Athlete[]
duree! : number;
groupe! : Groupe;
ligne! : Ligne[];
}
export class Activite{
@@ -54,24 +63,6 @@ export function getUserTest():User{
const s1 = new Session();
const s2 = new Session();
const s3 = new Session();
user.id = 0;
user.nom = "Emilien-Yee NootNoot";
user.role = "Coach"
s1.creneau = new Date();
s1.id = 1;
s1.name = "Entrainement Frisbee"
s1.isRecurrent = true;
var date2 = new Date();
date2.setDate(date2.getDate() + 2);
s2.creneau = date2;
s2.id = 2;
s2.isRecurrent = false;
s2.name = "entraintement 2"
s3.creneau = date2;
s3.id = 3;
s3.isRecurrent = false;
s3.name = "entraintement 3"
const athlete1 = new Athlete();
athlete1.id = 1;
athlete1.nom = "Alice Dupont";
@@ -87,6 +78,49 @@ export function getUserTest():User{
athlete3.nom = "Clara Lopez";
athlete3.groupe = "Loisir";
const ligne1 = new Ligne();
ligne1.id = 1;
ligne1.nom = "Ligne A";
ligne1.composition = [athlete1, athlete2]; // Alice + Bob
ligne1.tempsDeJeu = 45;
const ligne2 = new Ligne();
ligne2.id = 2;
ligne2.nom = "Ligne B";
ligne2.composition = [athlete2, athlete3]; // Bob + Clara
ligne2.tempsDeJeu = 40;
const ligne3 = new Ligne();
ligne3.id = 3;
ligne3.nom = "Ligne C";
ligne3.composition = [athlete1, athlete3]; // Alice + Clara
ligne3.tempsDeJeu = 50;
user.id = 0;
user.nom = "Emilien-Yee NootNoot";
user.role = "Coach"
s1.creneau = new Date();
s1.id = 1;
s1.name = "Entrainement Frisbee"
s1.isRecurrent = true;
s1.ligne = [ligne1];
var date2 = new Date();
date2.setDate(date2.getDate() + 2);
s2.creneau = date2;
s2.id = 2;
s2.isRecurrent = false;
s2.name = "entraintement 2"
s2.ligne = [ligne2];
s3.creneau = date2;
s3.id = 3;
s3.isRecurrent = false;
s3.name = "entraintement 3"
s3.ligne = [ligne3];
s1.athletes = [athlete1, athlete2];
s2.athletes = [athlete2, athlete3];
s3.athletes = [athlete1, athlete3];

View File

@@ -0,0 +1,75 @@
import { useState, useEffect } from "react";
import { Session, User, Coach, Activite, Groupe } from "../classes";
import { Modal } from "./Modal";
type CreateActiciteProps = {
returnActivite: (activite:Activite|null) => void
}
export function CreateActivite({ returnActivite }: CreateActiciteProps){
const [activities, setActivities] = useState<Activite[]>([]);
const [activiteNom, setActiviteNom] = useState("");
const [activiteTheme, setActiviteTheme] = useState("");
const [activiteDuree, setActiviteDuree] = useState(0);
function addAcitivte(){
if (!activiteNom) return;
const newActivite = new Activite();
newActivite.nom= activiteNom;
newActivite.theme=activiteTheme;
newActivite.duree= activiteDuree;
newActivite.data= new Map<string,string>();
setActivities([...activities, newActivite]);
setActiviteNom("");
setActiviteTheme("");
setActiviteDuree(0);
returnActivite(newActivite);
}
function cancel(){
returnActivite(null);
}
return (
<Modal isOpen={true} onClose={() => cancel()}>
<div className="edt_activite_modal">
<h2>Nouvelle Activité :</h2>
<div>
Nom de l'activité:
</div>
<div>
<input type="text" value={activiteNom} onChange={e => setActiviteNom(e.target.value)} />
</div>
<div>
Theme:
</div>
<div>
<input type="text" value={activiteTheme} onChange={e => setActiviteTheme(e.target.value)} />
</div>
<div>
Duree (minutes):
</div>
<div>
<input type="number" value={activiteDuree} onChange={e => setActiviteDuree(Number(e.target.value))} />
</div>
<button type="button" onClick={()=>addAcitivte()}>Ajouter l'activite</button>
<button type="button" onClick={()=>cancel()}>Annuler</button>
<ul>
{activities.map((act, idx) => (
<li key={idx}>{act.nom} - {act.theme} ({act.duree} min)</li>
))}
</ul>
</div>
</Modal>
);
};
export default CreateActivite;

View File

@@ -42,10 +42,7 @@ export const EDT =() =>{
var newWeek: Session[] = []
user.sessions.forEach(session => {
if( session.isRecurrent ){
newWeek.push(session);
}
if(session.creneau >= date && session.creneau <= maxDate && !session.isRecurrent){
if((session.creneau >= date && session.creneau <= maxDate && !session.isRecurrent) || session.isRecurrent){
newWeek.push(session);
}
});

View File

@@ -5,6 +5,7 @@ import './style/edt.css';
import { Modal } from './Modal';
import Loading from './loading';
import {delay} from "../requetes";
import CreateActivite from './createActivite';
type Props = {
@@ -13,21 +14,22 @@ type Props = {
function EdtSession({session}:Props){
const [open, setOpen] = useState<boolean>(false)
const [open, setOpen] = useState<boolean>(false);
const [open2, setOpen2] = useState<boolean>(false);
const [loading,setLoading] = useState<boolean>(false);
const [activites,setActivites] = useState<Activite[]>([]);
function handleOpen(): void {
setOpen(!open);
}
function handleDeleteActivite(): void {
session.activites.pop(); //TODO
function handleDeleteActivite(activite:Activite): void {
session.activites.splice(session.activites.indexOf(activite), 1);
setActivites([...session.activites])
}
function handleAddActivite(): void {
const newActivite = new Activite();
//TODO
session.activites.push(newActivite);
setOpen2(true)
}
async function updateActivites(){
@@ -45,7 +47,24 @@ function EdtSession({session}:Props){
}
},[open])
useEffect(() => {
if(!loading){
setActivites([...session.activites])
}
},[loading])
const sDate = session.creneau;
function returnActivite(activite: Activite|null){
if(activite!==null){
session.activites.push(activite);
setActivites([...session.activites])
}
setOpen2(false);
}
return(
<div>
<div className="edt_session" onClick={() => handleOpen()}>
@@ -64,16 +83,20 @@ function EdtSession({session}:Props){
<div>
Activités :
<div className="ent_activite_list">
{session.activites.map((activite,index)=>(
{activites.map((activite,index)=>(
<div>
{activite.nom}
<button className="deleteButton" onClick={() => handleDeleteActivite}>x</button>
<button className="deleteButton" onClick={() => handleDeleteActivite(activite)}>x</button>
</div>
))}
<button className="addButton" onClick={() => handleAddActivite}>+</button>
<button className="addButton" onClick={() => handleAddActivite()}>+</button>
{loading && <div className='edt_loading'><Loading/></div>}
</div>
</div>
{open2 &&
<CreateActivite returnActivite={(activite) => returnActivite(activite)}/>
}
</div>
</Modal>
}

View File

@@ -29,8 +29,19 @@ export const Login =() =>{
return(
<div>
<div>
Authenticated : {keycloak.authenticated ? 'oui' : 'non'}
Etat : {keycloak.authenticated ? 'connecté' : 'non connecté'}
</div>
{keycloak.authenticated &&
<div>
<div>
Keycloak ID : { keycloak.tokenParsed?.sub}
</div>
<div>
User nom : { user.nom}
</div>
</div>
}
<button onClick={() => handleLogin()}>
Se connecter
</button>

View File

@@ -1,9 +1,10 @@
import { Athlete, Activite, Coach, Session } from "../classes";
import { Athlete, Activite, Coach, Session, Ligne } from "../classes";
type AthleteListProps = { athletes: Athlete[] };
type ActiviteListProps = { activites: Activite[] };
type CoachListProps = { coachs: Coach[] };
type SessionListProps = { sessions: Session[]};
type LigneListProps = { lignes: Ligne[]};
function AthleteList({ athletes }: AthleteListProps) {
return (
@@ -70,6 +71,9 @@ function SessionList({ sessions }: SessionListProps) {
<div>
<strong>Coach:</strong> {sessions.coach ? sessions.coach.nom : "Pas de coach sur la séance"}
</div>
<div>
<strong>Ligne:</strong> {sessions.ligne ? sessions.ligne.map(ligne => ligne.nom).join(", ") : "Pas de ligne sur la séance"}
</div>
</li>
))}
@@ -77,4 +81,33 @@ function SessionList({ sessions }: SessionListProps) {
);
}
export { AthleteList, ActiviteList, CoachList , SessionList };
function LigneList({ lignes }: LigneListProps) {
return (
<ul className="LigneList">
{lignes.map((lignes) => (
<li key={lignes.id}>
<div>
<strong>Nom:</strong> {lignes.nom}
</div>
<div>
<div>
<strong>Composition :</strong>
<ul>
{lignes.composition.map((athlete) => (
<li key={athlete.id}>
{athlete.nom}
</li>
))}
</ul>
</div>
</div>
<div>
<strong>Temps de jeu: {lignes.tempsDeJeu}</strong>
</div>
</li>
))}
</ul>
);
}
export { AthleteList, ActiviteList, CoachList , SessionList, LigneList };

View File

@@ -1,125 +1,163 @@
import { useState } from "react";
import { useLocalData } from "../context/useLocalData";
import { AthleteList, ActiviteList, CoachList, SessionList} from "./ressourceList";
import { Activite, Athlete, Coach , Session } from "../classes";
import { useState } from "react";
import { useLocalData } from "../context/useLocalData";
import { AthleteList, ActiviteList, CoachList, SessionList, LigneList} from "./ressourceList";
import { Activite, Athlete, Coach , Session, Ligne } from "../classes";
export default function RessourcePanel() {
const { user } = useLocalData();
const [showAthletes, setShowAthletes] = useState(false);
const [showActivites, setShowActivites] = useState(false);
const [showCoachs,setShowCoachs] = useState(false);
const [showSessions, setShowSessions] = useState(false);
console.log("Rôle utilisateur:", user.role);
if (user.role === "Athlete") return null;
export default function RessourcePanel() {
const { user } = useLocalData();
const [showAthletes, setShowAthletes] = useState(false);
const [showActivites, setShowActivites] = useState(false);
const [showCoachs,setShowCoachs] = useState(false);
const [showSessions, setShowSessions] = useState(false);
const [showLignes, setShowLignes] = useState(false);
console.log("Rôle utilisateur:", user.role);
if (user.role === "Athlete") return null;
const athleteMap: Map<number, Athlete> = new Map();
user.sessions.forEach(session => {
session.athletes?.forEach(a => athleteMap.set(a.id, a));
});
const allAthletes: Athlete[] = Array.from(athleteMap.values());
const athleteMap: Map<number, Athlete> = new Map();
user.sessions.forEach(session => {
session.athletes?.forEach(a => athleteMap.set(a.id, a));
});
const allAthletes: Athlete[] = Array.from(athleteMap.values());
const activiteMap: Map<number, Activite> = new Map();
user.sessions.forEach(session => {
session.activites?.forEach(act => activiteMap.set(act.id, act));
});
const allActivites: Activite[] = Array.from(activiteMap.values());
const activiteMap: Map<number, Activite> = new Map();
user.sessions.forEach(session => {
session.activites?.forEach(act => activiteMap.set(act.id, act));
});
const allActivites: Activite[] = Array.from(activiteMap.values());
const coachMap: Map<number, Coach> = new Map();
user.sessions.forEach(session => {
if (session.coach) {
coachMap.set(session.coach.id, session.coach);
}
});
const coachMap: Map<number, Coach> = new Map();
user.sessions.forEach(session => {
if (session.coach) {
coachMap.set(session.coach.id, session.coach);
}
});
const allCoachs: Coach[] = Array.from(coachMap.values());
const allCoachs: Coach[] = Array.from(coachMap.values());
const sessionMap: Map<number, Session> = new Map();
user.sessions.forEach(session => {
sessionMap.set(session.id, session);
});
const sessionMap: Map<number, Session> = new Map();
user.sessions.forEach(session => {
sessionMap.set(session.id, session);
});
const allSessions: Session[] = Array.from(sessionMap.values());
const allSessions: Session[] = Array.from(sessionMap.values());
function onAthletesClick(): void {
setShowAthletes(prev => !prev);
setShowActivites(false);
setShowCoachs(false);
setShowSessions(false);
const ligneMap: Map<number, Ligne> = new Map();
user.sessions.forEach(session => {
if (session.ligne) {
}
function onActivitiesClick(): void {
setShowActivites(prev => !prev);
setShowAthletes(false);
setShowCoachs(false);
setShowSessions(false);
session.ligne.forEach(ligne => {
ligneMap.set(ligne.id, ligne);
});
}
});
const allLignes: Ligne[] = Array.from(ligneMap.values());
function onAthletesClick(): void {
setShowAthletes(prev => !prev);
setShowActivites(false);
setShowCoachs(false);
setShowSessions(false);
setShowLignes(false);
}
function onActivitiesClick(): void {
setShowActivites(prev => !prev);
setShowAthletes(false);
setShowCoachs(false);
setShowSessions(false);
setShowLignes(false);
}
function onCoachClick(): void {
setShowCoachs(prev => !prev);
setShowActivites(false);
setShowAthletes(false);
setShowSessions(false);
}
function onCoachClick(): void {
setShowCoachs(prev => !prev);
setShowActivites(false);
setShowAthletes(false);
setShowSessions(false);
setShowLignes(false);
}
}
function onSessionClick(): void {
setShowSessions(prev => !prev);
setShowActivites(false);
setShowAthletes(false);
setShowCoachs(false);
function onSessionClick(): void {
setShowSessions(prev => !prev);
setShowActivites(false);
setShowAthletes(false);
setShowCoachs(false);
setShowLignes(false);
}
}
function onLigneClick():void{
setShowLignes(prev => !prev);
setShowAthletes(false);
setShowActivites(false);
setShowCoachs(false);
setShowSessions(false);
}
return (
<div className="ressource_panel">
<select
onChange={(e) => {
const v = (e.target as HTMLSelectElement).value;
if (v === "athletes") onAthletesClick();
else if (v === "activites") onActivitiesClick();
else if (v === "coach") onCoachClick();
else if (v === "session") onSessionClick();
else {setShowAthletes(false); setShowActivites(false); setShowCoachs(false); setShowSessions(false)}
}}>
<option value="athletes">Athlètes</option>
<option value="activites">Activités</option>
{user.role === "Admin" && <option value="coach"> Coach</option>}
<option value="session"> Session</option>
</select>
return (
<div className="ressource_panel">
<div>
Sélectionner une ressource:
</div>
<select
onChange={(e) => {
const v = (e.target as HTMLSelectElement).value;
if (v === "athletes") onAthletesClick();
else if (v === "activites") onActivitiesClick();
else if (v === "coach") onCoachClick();
else if (v === "session") onSessionClick();
else if (v === "lignes") onLigneClick();
else {setShowAthletes(false); setShowActivites(false); setShowCoachs(false); setShowSessions(false)}
}}>
<option value="athletes">Athlètes</option>
<option value="activites">Activités</option>
{user.role === "Admin" && <option value="coach"> Coach</option>}
<option value="session"> Session</option>
<option value="lignes"> Lignes</option>
{showAthletes && (
<div className="edt_athletes_panel">
<h3>Liste des athlètes</h3>
<AthleteList athletes={allAthletes} />
</div>
)}
</select>
{showActivites && (
<div className="edt_activites_panel">
<h3>Liste des activités</h3>
<ActiviteList activites={allActivites} />
</div>
)}
{showAthletes && (
<div className="edt_athletes_panel">
<h3>Liste des athlètes</h3>
<AthleteList athletes={allAthletes} />
</div>
)}
{showCoachs && (
<div className="edt_coachs_panel">
<h3>Liste des coachs</h3>
<CoachList coachs={allCoachs} />
</div>
)}
{showActivites && (
<div className="edt_activites_panel">
<h3>Liste des activités</h3>
<ActiviteList activites={allActivites} />
</div>
)}
{showSessions && (
<div className="edt_sessions_panel">
<h3>Liste des sessions</h3>
<SessionList sessions={allSessions} />
</div>
)}
{showCoachs && (
<div className="edt_coachs_panel">
<h3>Liste des coachs</h3>
<CoachList coachs={allCoachs} />
</div>
)}
{showSessions && (
<div className="edt_sessions_panel">
<h3>Liste des sessions</h3>
<SessionList sessions={allSessions} />
</div>
)}
{showLignes && (
<div className="edt_lignes_panel">
<h3>Liste des lignes</h3>
<LigneList lignes={allLignes} />
</div>
)}
</div>
);
}
</div>
);
}

View File

@@ -119,3 +119,10 @@
background-color: var(--tint5);
border-radius: 10px;
}
.edt_activite_modal{
background-color: var(--tint3);
padding: 10px;
border-radius: 20px;
position: relative;
}

View File

@@ -1,14 +1,27 @@
import { getUsersAPI } from "../requetes"
import { useKeycloak } from "@react-keycloak/web"
import { getCoachsAPI, getUsersAPI, postAdmin } from "../requetes"
import { Admin } from "../classes";
function TestAPI(){
const { keycloak } = useKeycloak()
function handleGetUsers(): void {
getUsersAPI()
getCoachsAPI();
}
function handleSendAdmin(): void {
const admin = new Admin;
admin.nom = "admin";
admin.email = "admin@gmail.com";
postAdmin(admin);
}
return(
<div style={{padding:30, backgroundColor:"#000000"}}>
<button onClick={()=>handleGetUsers()}>getUsers</button>
<button onClick={()=>handleSendAdmin()}>sendAdmin</button>
</div>
)
}

View File

@@ -65,3 +65,10 @@ code {
transform: rotate(360deg);
}
}
input{
background-color: var(--tint2);
color: var(--test);
border-color: var(--tint5);
border-radius: 8px;
}

View File

@@ -1,15 +1,5 @@
import api from "./api";
import { Activite, Athlete, Coach, Session, User } from "./classes";
//import { useKeycloak } from '@react-keycloak/web'
import { useKeycloak } from '@react-keycloak/web'
import { useAuthHeader } from "./hook/useAuthHeader";
/*
const useAuthHeader = () => {
return keycloak?.token
? { Authorization: `Bearer ${keycloak.token}` }
: {}
}*/
import { Activite, Admin, Athlete, Coach, Session, User } from "./classes";
//debug:
export function delay(ms: number): Promise<void> {
@@ -63,7 +53,7 @@ export async function updateActivitiesOfSessionAPI(session:Session){
export async function subscribeSessionAPI(user:User, session:Session):Promise<boolean>{
try {
await api.post(`/sessions/${session.id}/subscribe`, { userId: user.id });
await api.post(`/sessions/${session.id}/subscribe`);
return true;
} catch (error) {
console.error("Error subscribing to session:", error);
@@ -73,7 +63,7 @@ export async function subscribeSessionAPI(user:User, session:Session):Promise<bo
export async function unsubscribeSessionAPI(user:User, session:Session):Promise<boolean>{
try {
await api.post(`/session/${session.id}/unsubscribe`, { userId: user.id });
await api.post(`/session/${session.id}/unsubscribe`);
return true;
} catch (error) {
console.error("Error unsubscribing from session:", error);
@@ -114,8 +104,26 @@ export async function postActivityAPI(session: Session, activity: Activite){
}
}
export async function postUser(user: User):Promise<boolean>{
return true;
export async function postAthlete(athlete: Athlete):Promise<Athlete>{
try {
const response = await api.post<Athlete>("/athlete/create/",athlete);
console.log(response);
return response.data;
} catch (error) {
console.error("Error fetching coachs:", error);
throw error;
}
}
export async function postAdmin(athlete: Admin):Promise<Admin>{
try {
const response = await api.post<Admin>("/admin/create/",athlete);
console.log(response);
return response.data;
} catch (error) {
console.error("Error fetching coachs:", error);
throw error;
}
}
// SET /////////////////////////////////////////////////////////
@@ -148,3 +156,14 @@ export async function getUsersAPI(): Promise<User[]> {
throw error;
}
}
export async function getCoachsAPI(): Promise<Coach[]> {
try {
const response = await api.get<Coach[]>("/coach/all");
console.log(response);
return response.data;
} catch (error) {
console.error("Error fetching coachs:", error);
throw error;
}
}

94
package-lock.json generated
View File

@@ -2,97 +2,5 @@
"name": "hackathon",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"react-router-dom": "^7.11.0"
}
},
"node_modules/cookie": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
"integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/react": {
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
"react": "^19.2.3"
}
},
"node_modules/react-router": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.11.0.tgz",
"integrity": "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
"set-cookie-parser": "^2.6.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
},
"node_modules/react-router-dom": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.11.0.tgz",
"integrity": "sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g==",
"license": "MIT",
"dependencies": {
"react-router": "7.11.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
},
"node_modules/scheduler": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"license": "MIT"
},
"node_modules/set-cookie-parser": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
"license": "MIT"
}
}
"packages": {}
}