Browse Source

Merge remote-tracking branch 'origin/test'

henri carmelo 11 months ago
parent
commit
dea9dc50ed
67 changed files with 4670 additions and 3875 deletions
  1. 9 0
      Jenkinsfile.rej
  2. 1 8
      angular-client/src/app/components/auth/gain/gain-list/gain-list.component.html
  3. 6 4
      angular-client/src/app/components/auth/gain/gain-list/gain-list.component.ts
  4. 68 36
      angular-client/src/app/components/auth/gain/gain.component.ts
  5. 2 2
      angular-client/src/app/components/home/home.component.html
  6. 12 25
      angular-client/src/app/services/auth.service.ts
  7. 1 1
      angular-client/src/app/services/statistic.service.ts
  8. 5 0
      angular-client/src/app/services/users.service.ts
  9. 2 2
      angular-client/src/environments/environment.ts
  10. 17 22
      docker-compose.yml
  11. 10 11
      express-server/Dockerfile
  12. 55 47
      express-server/controllers/gain.js
  13. 3 0
      express-server/index.js
  14. 3 3
      express-server/lib/db.js
  15. 7 0
      express-server/node_modules/body-parser/HISTORY.md
  16. 11 0
      express-server/node_modules/body-parser/README.md
  17. 52 12
      express-server/node_modules/body-parser/package.json
  18. 51 15
      express-server/node_modules/content-type/package.json
  19. 0 142
      express-server/node_modules/cookie/HISTORY.md
  20. 63 48
      express-server/node_modules/cookie/README.md
  21. 121 57
      express-server/node_modules/cookie/index.js
  22. 16 16
      express-server/node_modules/cookie/package.json
  23. 4 0
      express-server/node_modules/debug/package.json
  24. 1 0
      express-server/node_modules/depd/package.json
  25. 16 17
      express-server/node_modules/encodeurl/package.json
  26. 82 5
      express-server/node_modules/express/History.md
  27. 102 8
      express-server/node_modules/express/Readme.md
  28. 13 3
      express-server/node_modules/express/lib/response.js
  29. 1 1
      express-server/node_modules/express/lib/router/index.js
  30. 15 10
      express-server/node_modules/express/lib/router/route.js
  31. 3 4
      express-server/node_modules/express/lib/utils.js
  32. 24 21
      express-server/node_modules/express/package.json
  33. 15 0
      express-server/node_modules/finalhandler/HISTORY.md
  34. 2 2
      express-server/node_modules/finalhandler/README.md
  35. 7 2
      express-server/node_modules/finalhandler/index.js
  36. 17 16
      express-server/node_modules/finalhandler/package.json
  37. 1 1
      express-server/node_modules/iconv-lite/package.json
  38. 2 0
      express-server/node_modules/inherits/package.json
  39. 25 18
      express-server/node_modules/merge-descriptors/package.json
  40. 0 1
      express-server/node_modules/mime-types/package.json
  41. 2 1
      express-server/node_modules/mkdirp/package.json
  42. 1 3
      express-server/node_modules/ms/package.json
  43. 1 0
      express-server/node_modules/parseurl/package.json
  44. 13 13
      express-server/node_modules/path-to-regexp/package.json
  45. 6 0
      express-server/node_modules/qs/.editorconfig
  46. 5 5
      express-server/node_modules/qs/.eslintrc
  47. 213 1
      express-server/node_modules/qs/CHANGELOG.md
  48. 136 50
      express-server/node_modules/qs/README.md
  49. 56 2010
      express-server/node_modules/qs/dist/qs.js
  50. 46 13
      express-server/node_modules/qs/lib/parse.js
  51. 57 23
      express-server/node_modules/qs/lib/stringify.js
  52. 47 34
      express-server/node_modules/qs/lib/utils.js
  53. 46 28
      express-server/node_modules/qs/package.json
  54. 361 32
      express-server/node_modules/qs/test/parse.js
  55. 490 57
      express-server/node_modules/qs/test/stringify.js
  56. 5 0
      express-server/node_modules/raw-body/HISTORY.md
  57. 1 1
      express-server/node_modules/raw-body/README.md
  58. 7 0
      express-server/node_modules/raw-body/index.js
  59. 17 18
      express-server/node_modules/raw-body/package.json
  60. 2 5
      express-server/node_modules/safe-buffer/package.json
  61. 5 0
      express-server/node_modules/send/HISTORY.md
  62. 1 2
      express-server/node_modules/send/index.js
  63. 10 10
      express-server/node_modules/send/package.json
  64. 16 0
      express-server/node_modules/serve-static/HISTORY.md
  65. 12 12
      express-server/node_modules/serve-static/package.json
  66. 2262 991
      express-server/package-lock.json
  67. 7 6
      express-server/package.json

+ 9 - 0
Jenkinsfile.rej

@@ -0,0 +1,9 @@
+diff a/Jenkinsfile b/Jenkinsfile	(rejected hunks)
+@@ -9,6 +9,7 @@
+     stage('checkout') {
+         deleteDir()
+         checkout scm
++        sh "git checkout test"
+     }
+      
+     stage('Stop Containers') {

+ 1 - 8
angular-client/src/app/components/auth/gain/gain-list/gain-list.component.html

@@ -1,13 +1,8 @@
- <!-- table of users -->
-<<<<<<<<< Temporary merge branch 1
-=========
+<!-- table of users -->
 
->>>>>>> test
     <table *ngIf="lots" mat-table  [dataSource]="lots" class="tablegain">
 
->>>>>>> dev
 
-      <!-- *ngIf="lots" -->
       <!-- index -->
       <ng-container matColumnDef="index">
         <th mat-header-cell *matHeaderCellDef> Numéro </th>
@@ -58,5 +53,3 @@
       (page)="handlePage($event)">
     </mat-paginator> -->
 
-
-

+ 6 - 4
angular-client/src/app/components/auth/gain/gain-list/gain-list.component.ts

@@ -11,6 +11,10 @@ export class GainListComponent implements OnInit  {
 
   constructor() { }
 
+  ngOnInit() {
+    this.dataSource.data = this.lots;
+  }
+
   @Input() lots : Ticket[]=[];
 
 
@@ -29,9 +33,7 @@ export class GainListComponent implements OnInit  {
     // })
   
   }
-   ngOnInit() {
-    this.dataSource.data = this.lots;
-  }
+   
   
   
-}
+}

+ 68 - 36
angular-client/src/app/components/auth/gain/gain.component.ts

@@ -8,52 +8,84 @@ import { ActivatedRoute } from '@angular/router';
 @Component({
   selector: 'app-gain',
   templateUrl: './gain.component.html',
-  styleUrls: ['./gain.component.scss']
+  styleUrls: ['./gain.component.scss'],
 })
 export class GainComponent implements OnInit {
+  token: string; // JWT token extrait de l'URL
+  @Input() lots: Ticket[] = []; // Liste des gains
+  user: User; // Informations utilisateur
 
-  token: string;
-
-  constructor(private authService : AuthService, private route: ActivatedRoute,  private userService : UsersService)
-   { }
-
-  //  @Input() lots;
-   @Input() lots:Ticket[];
-  user : User;
+  constructor(
+    private authService: AuthService,
+    private route: ActivatedRoute,
+    private userService: UsersService
+  ) {}
 
   ngOnInit(): void {
-     this.getInfoUser()
-     // Récupérer le token JWT de l'URL
-     this.route.queryParams.subscribe(params => {
-      this.token = params['token'];
-  });
+    // Charger les informations utilisateur et initialiser les gains
+    this.getInfoUser();
 
+    // Extraire le token JWT depuis les paramètres de l'URL
+    this.route.queryParams.subscribe((params) => {
+      this.token = params['token'];
+    });
   }
 
-  getInfoUser(){
-     this.authService.getUserInfo().subscribe( (user) =>{ this.user = user, this.lots = user.gains})
+  /**
+   * Récupère les informations utilisateur depuis l'API AuthService
+   */
+  getInfoUser(): void {
+    this.authService.getUserInfo().subscribe(
+      (user) => {
+        this.user = user;
+        this.lots = user.gains || []; // Initialiser les gains à partir des données utilisateur
+      },
+      (err) => {
+        console.error('Erreur lors de la récupération des informations utilisateur :', err);
+        this.authService.openSnackBar('Impossible de charger les informations utilisateur.');
+      }
+    );
   }
 
-
-  receiveCode($event : Ticket){
-    let id = this.authService.userValue._id
-    this.userService.verifyLotUser(id, $event).subscribe( (res) => {
-      if(res) {
-      this.lots = [];
-      this.lots.push(res);
+  /**
+   * Vérifie un gain et met à jour la liste des gains
+   * @param $event Ticket - Le ticket à vérifier
+   */
+  receiveCode($event: Ticket): void {
+    const userId = this.authService.userValue._id; // ID utilisateur récupéré depuis AuthService
+  
+    // Vérifier le ticket avec l'API UsersService
+    this.userService.verifyLotUser(userId, $event).subscribe(
+      (res) => {
+        if (res) {
+          // Ajouter le ticket vérifié à la liste locale
+          this.lots = [...this.lots, res];
+  
+          // Mettre à jour les gains côté serveur
+          this.userService.updateUserGains(userId, this.lots).subscribe(
+            () => {
+              console.log('Gains sauvegardés avec succès dans le backend.');
+              this.authService.openSnackBar('Gain ajouté avec succès !');
+  
+              // Recharger les informations utilisateur pour s'assurer que les gains sont à jour
+              this.getInfoUser();
+            },
+            (err) => {
+              console.error('Erreur lors de la sauvegarde des gains :', err);
+              this.authService.openSnackBar(
+                `Erreur lors de la sauvegarde des gains : ${err.error?.message || 'Erreur inconnue.'}`
+              );
+            }
+          );
+        }
+      },
+      (err) => {
+        console.error('Erreur lors de la vérification du ticket :', err);
+        this.authService.openSnackBar(err.error?.message || 'Erreur lors de la vérification du ticket.');
       }
-    },
-
-    err => {
-      console.log(err.error.message)
-      this.authService.openSnackBar(err.error.message)
+    );
+  
+    console.log('Liste des gains après ajout :', this.lots);
   }
-      ); 
-       console.log(' Retour de la requete',this.lots)
-  }
-
-
-
-
-
+  
 }

+ 2 - 2
angular-client/src/app/components/home/home.component.html

@@ -3,8 +3,8 @@
          <h1 class="text-center  gain mb-4">jeu-concours</h1>
 
     <div class="range">
-        <h2 class="text-center  gain mb-4">Tentez de gagner un Range Rover</h2>
-        <h3 class="text-center concours font-weight-bold">Du 16 juillet 2020 au 16 septembre 2020</h3>
+        <h2 class="text-center  gain mb-4">Tentez de gagner un Range Rover </h2>
+        <h3 class="text-center concours font-weight-bold">Du 16 juillet 2020 au 16 septembre 2024</h3>
         <h4 class="text-center concours">Pour tout achat d'une valeur de 18€ ou plus dans l'un de nos restaurants reçoit un code
             Promo</h4>
 

+ 12 - 25
angular-client/src/app/services/auth.service.ts

@@ -163,33 +163,20 @@ resetPassword(data): Observable<any> {
     },1000)
   }
 
-  getUserInfo(): Observable<User> {
-    let token = this.tokenSubject.value.token;
-    if (token) {
-      // User is authenticated locally
-      let decodedToken: payloadToken = jwt_decode(token);
-      return this.http.get<User>(`${this.apiUrl}/api/users/${decodedToken.userId}`).pipe(
-        map(user => {
-          // Store user info in local storage
-          localStorage.setItem('user', JSON.stringify(user));
-          this.user_infoSubject.next(user);
-          return user;
-        })
-      );
-    } else {
-      // User is authenticated via Google
-      return this.http.get<User>(`${this.apiUrl}/api/auth/google`).pipe(
-        map(user => {
-          // Store user info in local storage
-          localStorage.setItem('user', JSON.stringify(user));
-          this.user_infoSubject.next(user);
-          return user;
-        })
-      );
-    }
+   // get info user 
+   getUserInfo(): Observable<User> {
+    
+    let decodedToken : payloadToken = jwt_decode(this.tokenSubject.value.token); 
+    return this.http.get<User>(`${this.apiUrl}/api/users/${decodedToken.userId}`)
+      .pipe(map(user => {
+        // store user info in local storage 
+        localStorage.setItem('user', JSON.stringify(user));
+        this.user_infoSubject.next(user);
+        return user; 
+      }));
+    
   }
   
-  
 
   openSnackBar(message: string) {
     this.snackBar.openFromComponent(AlertMessageComponent, {

+ 1 - 1
angular-client/src/app/services/statistic.service.ts

@@ -28,7 +28,7 @@ private headers = new HttpHeaders(
 getStatistic(): Observable<StatisticResponse> {
 //  return this.http.get<StatisticResponse>('assets/data/stat.json');
 const options = { headers: this.headers};
- let data = this.http.get<StatisticResponse>('https://api-prod.foodgame.fr/api/tickets/stats',options);
+ let data = this.http.get<StatisticResponse>(`${this.apiUrl}/api/tickets/stats`,options);
  console.log(JSON.stringify(data));
  return data;
  

+ 5 - 0
angular-client/src/app/services/users.service.ts

@@ -51,6 +51,11 @@ verifyLotUser(id:string, code: Ticket): Observable <Ticket> {
   
 }
 
+updateUserGains(userId: string, gains: Ticket[]) {
+  return this.http.put(`${this.apiUrl}/api/users/${userId}/gains`, { gains });
+}
+
+
 
 }
 

+ 2 - 2
angular-client/src/environments/environment.ts

@@ -4,8 +4,8 @@
 
 export const environment = {
   production: false,
-  name: "(Dev)",
-  apiUrl: `http://api-dev.foodgame.fr`,
+  name: "(Test)",
+  apiUrl: `http://localhost:4000`,
 };
 
 /*

+ 17 - 22
docker-compose.yml

@@ -39,28 +39,23 @@ networks:
 
 services:
   express_preprod:
-    #   container_name: express_"${ENV}"
-        build: express-server
-        ports:
-          - "4000:4000"
-        networks:
-          - web
-          - private
-          #- pipeline-test-mean-stack-docker_default
-          #- pipeline-test-mean-stack-docker_private
-          #- grafana
-        volumes:
-          - /var/log:/var/www/app/log/root
-        labels:
-          - traefik.enable=true
-          - traefik.http.routers.express_preprod.rule=Host(`api-preprod.foodgame.fr`)
-    #     - traefik.http.routers.apache_prod.rule=Host(`${URLEXPRESS}`)
-          - traefik.http.services.express_preprod.loadbalancer.server.port=4000
-          - traefik.http.routers.express_preprod.entrypoints=websecure
-          - traefik.http.routers.express_preprod.tls.certresolver=myresolver
-        links:
-          - database_preprod
-        restart: always
+    build:
+      context: ./express-server
+    ports:
+      - "4000:4000"
+    networks:
+      - web
+      - private
+    labels:
+      - traefik.enable=true
+      - traefik.http.routers.express_preprod.rule=Host(`api-preprod.foodgame.fr`)
+      - traefik.http.services.express_preprod.loadbalancer.server.port=4000
+      - traefik.http.routers.express_preprod.entrypoints=websecure
+      - traefik.http.routers.express_preprod.tls.certresolver=myresolver
+    links:
+      - database_preprod
+    restart: always
+
 
   database_preprod:
 #   container_name: mongo_"${ENV}"

+ 10 - 11
express-server/Dockerfile

@@ -1,13 +1,12 @@
-FROM node:10
-RUN mkdir -p /var/www/app
-WORKDIR /var/www/app
-COPY package.json /var/www/app
-RUN npm cache verify
-#RUN npm cache clean
+FROM node:12
+
+WORKDIR /usr/src/app
+
+COPY ./package*.json ./
 RUN npm install
-RUN npm install -g nodemon
-COPY . /var/www/app
-#EXPOSE 4000
-EXPOSE 9991
-CMD ["node","index.js"]
 
+COPY . .
+
+EXPOSE 4000
+
+CMD ["npm", "start"]

+ 55 - 47
express-server/controllers/gain.js

@@ -4,52 +4,60 @@ const { User } = require('../models/user.model');
 
 
 //consulter les gains
-exports.gain = async (req, res, next) => {
-
+exports.gain = async (req, res) => {
     try {
-        
-        // génère une exception
-        if (!req.query.id) { throw new Error(`Identifiant utilisateur introuvable`) }
-        if (!req.body.code) { throw new Error(`Code introuvable`) }
-        if (isNaN(req.body.code)) { throw new Error(`Votre code n'est pas un chiffre`) }
-        if (req.body.code.toString().length != 10) { throw new Error(`Votre code est différent de 10 chiffres`) }
-
-        
-        User.findById(req.query.id)
-            .then((user) => {
-
-                Ticket.findOne({ code: req.body.code })
-                      .then((ticket) => {
-                        
-                        if (ticket) {
-                            if (ticket.isUsed === false) {
-
-                                ticket.isUsed = true;
-                                ticket.date_used = new Date();
-                                res.send(ticket);
-                                
-
-                                ticket.save()
-                                      .then((ticket) => {
-                                        user.isGain = true;
-                                        // user.gains.push(ticket);
-                                        user.save()
-                                            .then(() => res.status(200).send(ticket))
-                                            .catch(() => res.status(500).json({ success: false, message: `Erreur dans le serveur` }))
-                                    })
-                                      .catch(() => res.status(500).json({ success: false, message: `Erreur dans le serveur` }))
-
-                            } else { res.status(400).json({ success: false, message: `Le code a déjà été utilisé` }) }
-                        } else { res.status(400).json({ success: false, message: `Le code est erroné` }) }
-
-                    })
-                       .catch(() => res.status(500).json({ success: false, message: `Erreur dans le serveur` }));
-                       return;
-
-            })
-            .catch(() => res.status(404).json({ success: false, message: `Utilisateur non trouvé` }))
-
+      // Vérifications initiales
+      const userId = req.query.id;
+      const ticketCode = req.body.code;
+  
+      if (!userId) {
+        return res.status(400).json({ success: false, message: `Identifiant utilisateur introuvable` });
+      }
+  
+      if (!ticketCode) {
+        return res.status(400).json({ success: false, message: `Code introuvable` });
+      }
+  
+      if (isNaN(ticketCode)) {
+        return res.status(400).json({ success: false, message: `Votre code n'est pas un chiffre` });
+      }
+  
+      if (ticketCode.toString().length !== 10) {
+        return res.status(400).json({ success: false, message: `Votre code est différent de 10 chiffres` });
+      }
+  
+      // Récupérer l'utilisateur
+      const user = await User.findById(userId);
+      if (!user) {
+        return res.status(404).json({ success: false, message: `Utilisateur non trouvé` });
+      }
+  
+      // Vérifier l'existence du ticket
+      const ticket = await Ticket.findOne({ code: ticketCode });
+      if (!ticket) {
+        return res.status(400).json({ success: false, message: `Le code est erroné` });
+      }
+  
+      // Vérifier si le ticket a déjà été utilisé
+      if (ticket.isUsed) {
+        return res.status(400).json({ success: false, message: `Le code a déjà été utilisé` });
+      }
+  
+      // Mettre à jour le ticket
+      ticket.isUsed = true;
+      ticket.date_used = new Date();
+      await ticket.save();
+  
+      // Ajouter le ticket à l'utilisateur et sauvegarder
+      user.isGain = true;
+      user.gains.push(ticket);
+      await user.save();
+  
+      // Répondre avec le ticket mis à jour
+      return res.status(200).json({ success: true, ticket });
+    } catch (err) {
+      console.error('Erreur dans le traitement du gain :', err.message);
+      return res.status(500).json({ success: false, message: `Erreur dans le serveur` });
     }
-    catch (err) { res.status(400).json({ success: false, message: err.message }) }
-    
-};
+  };
+  

+ 3 - 0
express-server/index.js

@@ -4,6 +4,9 @@ const passport = require('passport');
 const mongoose = require('mongoose');
 const session = require('express-session');
 const cors = require('cors');
+const { TextEncoder, TextDecoder } = require('util');
+global.TextEncoder = TextEncoder;
+global.TextDecoder = TextDecoder;
 // const config = require('./config/db.config');
 
 

+ 3 - 3
express-server/lib/db.js

@@ -1,13 +1,13 @@
 const mongoose = require('mongoose');
-const  config  = require('../config/config.json');
+//const  config  = require('../config/config.json');
 //const { Ticket } = require('../models/ticket.model');
 //const { Restaurant} = require('../models/restaurant.model');
 // const { User } = require('../models/user.model');
  //const bcrypt = require('bcrypt');
 // const Role = require('../lib/role');
-const db = config.url;
+//const db = config.url;
 
-//var db = 'mongodb://database_preprod:27017/mean-fatboar-db';
+var db = 'mongodb://database_preprod:27017/mean-fatboar-db';
 //var mongoURI = 'mongodb://localhost:27017/my-db';
 //mongoose.set('useCreateIndex', true)
 mongoose.connect(db, {useNewUrlParser: true, useUnifiedTopology: true })

+ 7 - 0
express-server/node_modules/body-parser/HISTORY.md

@@ -1,3 +1,10 @@
+1.20.3 / 2024-09-10
+===================
+
+  * deps: qs@6.13.0
+  * add `depth` option to customize the depth level in the parser
+  * IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
+
 1.20.2 / 2023-02-21
 ===================
 

+ 11 - 0
express-server/node_modules/body-parser/README.md

@@ -4,6 +4,7 @@
 [![NPM Downloads][npm-downloads-image]][npm-url]
 [![Build Status][ci-image]][ci-url]
 [![Test Coverage][coveralls-image]][coveralls-url]
+[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
 
 Node.js body parsing middleware.
 
@@ -277,6 +278,10 @@ The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`
 where `buf` is a `Buffer` of the raw request body and `encoding` is the
 encoding of the request. The parsing can be aborted by throwing an error.
 
+#### depth
+
+The `depth` option is used to configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible.
+
 ## Errors
 
 The middlewares provided by this module create errors using the
@@ -373,6 +378,10 @@ as well as in the `encoding` property. The `status` property is set to `415`,
 the `type` property is set to `'encoding.unsupported'`, and the `encoding`
 property is set to the encoding that is unsupported.
 
+### The input exceeded the depth
+
+This error occurs when using `bodyParser.urlencoded` with the `extended` property set to `true` and the input exceeds the configured `depth` option. The `status` property is set to `400`. It is recommended to review the `depth` option and evaluate if it requires a higher value. When the `depth` option is set to `32` (default value), the error will not be thrown.
+
 ## Examples
 
 ### Express/Connect top-level generic
@@ -463,3 +472,5 @@ app.use(bodyParser.text({ type: 'text/html' }))
 [npm-downloads-image]: https://badgen.net/npm/dm/body-parser
 [npm-url]: https://npmjs.org/package/body-parser
 [npm-version-image]: https://badgen.net/npm/v/body-parser
+[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/body-parser/badge
+[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/body-parser

+ 52 - 12
express-server/node_modules/body-parser/package.json

@@ -1,13 +1,43 @@
 {
-  "name": "body-parser",
-  "description": "Node.js body parsing middleware",
-  "version": "1.20.2",
+  "_from": "body-parser@^1.20.2",
+  "_id": "body-parser@1.20.3",
+  "_inBundle": false,
+  "_integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+  "_location": "/body-parser",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "body-parser@^1.20.2",
+    "name": "body-parser",
+    "escapedName": "body-parser",
+    "rawSpec": "^1.20.2",
+    "saveSpec": null,
+    "fetchSpec": "^1.20.2"
+  },
+  "_requiredBy": [
+    "/",
+    "/express"
+  ],
+  "_resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+  "_shasum": "1953431221c6fb5cd63c4b36d53fab0928e548c6",
+  "_spec": "body-parser@^1.20.2",
+  "_where": "C:\\FatboarProject\\express-server",
+  "bugs": {
+    "url": "https://github.com/expressjs/body-parser/issues"
+  },
+  "bundleDependencies": false,
   "contributors": [
-    "Douglas Christopher Wilson <doug@somethingdoug.com>",
-    "Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
+    {
+      "name": "Douglas Christopher Wilson",
+      "email": "doug@somethingdoug.com"
+    },
+    {
+      "name": "Jonathan Ong",
+      "email": "me@jongleberry.com",
+      "url": "http://jongleberry.com"
+    }
   ],
-  "license": "MIT",
-  "repository": "expressjs/body-parser",
   "dependencies": {
     "bytes": "3.1.2",
     "content-type": "~1.0.5",
@@ -17,11 +47,13 @@
     "http-errors": "2.0.0",
     "iconv-lite": "0.4.24",
     "on-finished": "2.4.1",
-    "qs": "6.11.0",
+    "qs": "6.13.0",
     "raw-body": "2.5.2",
     "type-is": "~1.6.18",
     "unpipe": "1.0.0"
   },
+  "deprecated": false,
+  "description": "Node.js body parsing middleware",
   "devDependencies": {
     "eslint": "8.34.0",
     "eslint-config-standard": "14.1.1",
@@ -36,6 +68,10 @@
     "safe-buffer": "5.2.1",
     "supertest": "6.3.3"
   },
+  "engines": {
+    "node": ">= 0.8",
+    "npm": "1.2.8000 || >= 1.4.16"
+  },
   "files": [
     "lib/",
     "LICENSE",
@@ -43,14 +79,18 @@
     "SECURITY.md",
     "index.js"
   ],
-  "engines": {
-    "node": ">= 0.8",
-    "npm": "1.2.8000 || >= 1.4.16"
+  "homepage": "https://github.com/expressjs/body-parser#readme",
+  "license": "MIT",
+  "name": "body-parser",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/expressjs/body-parser.git"
   },
   "scripts": {
     "lint": "eslint .",
     "test": "mocha --require test/support/env --reporter spec --check-leaks --bail test/",
     "test-ci": "nyc --reporter=lcov --reporter=text npm test",
     "test-cov": "nyc --reporter=html --reporter=text npm test"
-  }
+  },
+  "version": "1.20.3"
 }

+ 51 - 15
express-server/node_modules/content-type/package.json

@@ -1,17 +1,38 @@
 {
-  "name": "content-type",
-  "description": "Create and parse HTTP Content-Type header",
-  "version": "1.0.5",
-  "author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
-  "license": "MIT",
-  "keywords": [
-    "content-type",
-    "http",
-    "req",
-    "res",
-    "rfc7231"
+  "_from": "content-type@~1.0.4",
+  "_id": "content-type@1.0.5",
+  "_inBundle": false,
+  "_integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+  "_location": "/content-type",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "content-type@~1.0.4",
+    "name": "content-type",
+    "escapedName": "content-type",
+    "rawSpec": "~1.0.4",
+    "saveSpec": null,
+    "fetchSpec": "~1.0.4"
+  },
+  "_requiredBy": [
+    "/body-parser",
+    "/express"
   ],
-  "repository": "jshttp/content-type",
+  "_resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+  "_shasum": "8b773162656d1d1086784c8f23a54ce6d73d7918",
+  "_spec": "content-type@~1.0.4",
+  "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
+  "author": {
+    "name": "Douglas Christopher Wilson",
+    "email": "doug@somethingdoug.com"
+  },
+  "bugs": {
+    "url": "https://github.com/jshttp/content-type/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Create and parse HTTP Content-Type header",
   "devDependencies": {
     "deep-equal": "1.0.1",
     "eslint": "8.32.0",
@@ -23,14 +44,28 @@
     "mocha": "10.2.0",
     "nyc": "15.1.0"
   },
+  "engines": {
+    "node": ">= 0.6"
+  },
   "files": [
     "LICENSE",
     "HISTORY.md",
     "README.md",
     "index.js"
   ],
-  "engines": {
-    "node": ">= 0.6"
+  "homepage": "https://github.com/jshttp/content-type#readme",
+  "keywords": [
+    "content-type",
+    "http",
+    "req",
+    "res",
+    "rfc7231"
+  ],
+  "license": "MIT",
+  "name": "content-type",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/jshttp/content-type.git"
   },
   "scripts": {
     "lint": "eslint .",
@@ -38,5 +73,6 @@
     "test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
     "test-cov": "nyc --reporter=html --reporter=text npm test",
     "version": "node scripts/version-history.js && git add HISTORY.md"
-  }
+  },
+  "version": "1.0.5"
 }

+ 0 - 142
express-server/node_modules/cookie/HISTORY.md

@@ -1,142 +0,0 @@
-0.5.0 / 2022-04-11
-==================
-
-  * Add `priority` option
-  * Fix `expires` option to reject invalid dates
-  * pref: improve default decode speed
-  * pref: remove slow string split in parse
-
-0.4.2 / 2022-02-02
-==================
-
-  * pref: read value only when assigning in parse
-  * pref: remove unnecessary regexp in parse
-
-0.4.1 / 2020-04-21
-==================
-
-  * Fix `maxAge` option to reject invalid values
-
-0.4.0 / 2019-05-15
-==================
-
-  * Add `SameSite=None` support
-
-0.3.1 / 2016-05-26
-==================
-
-  * Fix `sameSite: true` to work with draft-7 clients
-    - `true` now sends `SameSite=Strict` instead of `SameSite`
-
-0.3.0 / 2016-05-26
-==================
-
-  * Add `sameSite` option
-    - Replaces `firstPartyOnly` option, never implemented by browsers
-  * Improve error message when `encode` is not a function
-  * Improve error message when `expires` is not a `Date`
-
-0.2.4 / 2016-05-20
-==================
-
-  * perf: enable strict mode
-  * perf: use for loop in parse
-  * perf: use string concatination for serialization
-
-0.2.3 / 2015-10-25
-==================
-
-  * Fix cookie `Max-Age` to never be a floating point number
-
-0.2.2 / 2015-09-17
-==================
-
-  * Fix regression when setting empty cookie value
-    - Ease the new restriction, which is just basic header-level validation
-  * Fix typo in invalid value errors
-
-0.2.1 / 2015-09-17
-==================
-
-  * Throw on invalid values provided to `serialize`
-    - Ensures the resulting string is a valid HTTP header value
-
-0.2.0 / 2015-08-13
-==================
-
-  * Add `firstPartyOnly` option
-  * Throw better error for invalid argument to parse
-  * perf: hoist regular expression
-
-0.1.5 / 2015-09-17
-==================
-
-  * Fix regression when setting empty cookie value
-    - Ease the new restriction, which is just basic header-level validation
-  * Fix typo in invalid value errors
-
-0.1.4 / 2015-09-17
-==================
-
-  * Throw better error for invalid argument to parse
-  * Throw on invalid values provided to `serialize`
-    - Ensures the resulting string is a valid HTTP header value
-
-0.1.3 / 2015-05-19
-==================
-
-  * Reduce the scope of try-catch deopt
-  * Remove argument reassignments
-
-0.1.2 / 2014-04-16
-==================
-
-  * Remove unnecessary files from npm package
-
-0.1.1 / 2014-02-23
-==================
-
-  * Fix bad parse when cookie value contained a comma
-  * Fix support for `maxAge` of `0`
-
-0.1.0 / 2013-05-01
-==================
-
-  * Add `decode` option
-  * Add `encode` option
-
-0.0.6 / 2013-04-08
-==================
-
-  * Ignore cookie parts missing `=`
-
-0.0.5 / 2012-10-29
-==================
-
-  * Return raw cookie value if value unescape errors
-
-0.0.4 / 2012-06-21
-==================
-
-  * Use encode/decodeURIComponent for cookie encoding/decoding
-    - Improve server/client interoperability
-
-0.0.3 / 2012-06-06
-==================
-
-  * Only escape special characters per the cookie RFC
-
-0.0.2 / 2012-06-01
-==================
-
-  * Fix `maxAge` option to not throw error
-
-0.0.1 / 2012-05-28
-==================
-
-  * Add more tests
-
-0.0.0 / 2012-05-28
-==================
-
-  * Initial release

+ 63 - 48
express-server/node_modules/cookie/README.md

@@ -2,9 +2,9 @@
 
 [![NPM Version][npm-version-image]][npm-url]
 [![NPM Downloads][npm-downloads-image]][npm-url]
-[![Node.js Version][node-version-image]][node-version-url]
-[![Build Status][github-actions-ci-image]][github-actions-ci-url]
-[![Test Coverage][coveralls-image]][coveralls-url]
+[![Node.js Version][node-image]][node-url]
+[![Build Status][ci-image]][ci-url]
+[![Coverage Status][coveralls-image]][coveralls-url]
 
 Basic HTTP cookie parser and serializer for HTTP servers.
 
@@ -107,6 +107,17 @@ The given number will be converted to an integer by rounding down. By default, n
 `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
 so if both are set, they should point to the same date and time.
 
+##### partitioned
+
+Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies)
+attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the
+`Partitioned` attribute is not set.
+
+**note** This is an attribute that has not yet been fully standardized, and may change in the future.
+This also means many clients may ignore this attribute until they understand it.
+
+More information about can be found in [the proposal](https://github.com/privacycg/CHIPS).
+
 ##### path
 
 Specifies the value for the [`Path` `Set-Cookie` attribute][rfc-6265-5.2.4]. By default, the path
@@ -212,49 +223,52 @@ $ npm test
 ```
 $ npm run bench
 
-> cookie@0.4.2 bench
+> cookie@0.5.0 bench
 > node benchmark/index.js
 
-  node@16.14.0
-  v8@9.4.146.24-node.20
-  uv@1.43.0
-  zlib@1.2.11
+  node@18.18.2
+  acorn@8.10.0
+  ada@2.6.0
+  ares@1.19.1
   brotli@1.0.9
-  ares@1.18.1
-  modules@93
-  nghttp2@1.45.1
-  napi@8
-  llhttp@6.0.4
-  openssl@1.1.1m+quic
-  cldr@40.0
-  icu@70.1
-  tz@2021a3
-  unicode@14.0
-  ngtcp2@0.1.0-DEV
-  nghttp3@0.1.0-DEV
+  cldr@43.1
+  icu@73.2
+  llhttp@6.0.11
+  modules@108
+  napi@9
+  nghttp2@1.57.0
+  nghttp3@0.7.0
+  ngtcp2@0.8.1
+  openssl@3.0.10+quic
+  simdutf@3.2.14
+  tz@2023c
+  undici@5.26.3
+  unicode@15.0
+  uv@1.44.2
+  uvwasi@0.0.18
+  v8@10.2.154.26-node.26
+  zlib@1.2.13.1-motley
 
 > node benchmark/parse-top.js
 
   cookie.parse - top sites
 
-  15 tests completed.
-
-  parse accounts.google.com x 2,421,245 ops/sec ±0.80% (188 runs sampled)
-  parse apple.com           x 2,684,710 ops/sec ±0.59% (189 runs sampled)
-  parse cloudflare.com      x 2,231,418 ops/sec ±0.76% (186 runs sampled)
-  parse docs.google.com     x 2,316,357 ops/sec ±1.28% (187 runs sampled)
-  parse drive.google.com    x 2,363,543 ops/sec ±0.49% (189 runs sampled)
-  parse en.wikipedia.org    x   839,414 ops/sec ±0.53% (189 runs sampled)
-  parse linkedin.com        x   553,797 ops/sec ±0.63% (190 runs sampled)
-  parse maps.google.com     x 1,314,779 ops/sec ±0.72% (189 runs sampled)
-  parse microsoft.com       x   153,783 ops/sec ±0.53% (190 runs sampled)
-  parse play.google.com     x 2,249,574 ops/sec ±0.59% (187 runs sampled)
-  parse plus.google.com     x 2,258,682 ops/sec ±0.60% (188 runs sampled)
-  parse sites.google.com    x 2,247,069 ops/sec ±0.68% (189 runs sampled)
-  parse support.google.com  x 1,456,840 ops/sec ±0.70% (187 runs sampled)
-  parse www.google.com      x 1,046,028 ops/sec ±0.58% (188 runs sampled)
-  parse youtu.be            x   937,428 ops/sec ±1.47% (190 runs sampled)
-  parse youtube.com         x   963,878 ops/sec ±0.59% (190 runs sampled)
+  14 tests completed.
+
+  parse accounts.google.com x 2,588,913 ops/sec ±0.74% (186 runs sampled)
+  parse apple.com           x 2,370,002 ops/sec ±0.69% (186 runs sampled)
+  parse cloudflare.com      x 2,213,102 ops/sec ±0.88% (188 runs sampled)
+  parse docs.google.com     x 2,194,157 ops/sec ±1.03% (184 runs sampled)
+  parse drive.google.com    x 2,265,084 ops/sec ±0.79% (187 runs sampled)
+  parse en.wikipedia.org    x   457,099 ops/sec ±0.81% (186 runs sampled)
+  parse linkedin.com        x   504,407 ops/sec ±0.89% (186 runs sampled)
+  parse maps.google.com     x 1,230,959 ops/sec ±0.98% (186 runs sampled)
+  parse microsoft.com       x   926,294 ops/sec ±0.88% (184 runs sampled)
+  parse play.google.com     x 2,311,338 ops/sec ±0.83% (185 runs sampled)
+  parse support.google.com  x 1,508,850 ops/sec ±0.86% (186 runs sampled)
+  parse www.google.com      x 1,022,582 ops/sec ±1.32% (182 runs sampled)
+  parse youtu.be            x   332,136 ops/sec ±1.02% (185 runs sampled)
+  parse youtube.com         x   323,833 ops/sec ±0.77% (183 runs sampled)
 
 > node benchmark/parse.js
 
@@ -262,12 +276,12 @@ $ npm run bench
 
   6 tests completed.
 
-  simple      x 2,745,604 ops/sec ±0.77% (185 runs sampled)
-  decode      x   557,287 ops/sec ±0.60% (188 runs sampled)
-  unquote     x 2,498,475 ops/sec ±0.55% (189 runs sampled)
-  duplicates  x   868,591 ops/sec ±0.89% (187 runs sampled)
-  10 cookies  x   306,745 ops/sec ±0.49% (190 runs sampled)
-  100 cookies x    22,414 ops/sec ±2.38% (182 runs sampled)
+  simple      x 3,214,032 ops/sec ±1.61% (183 runs sampled)
+  decode      x   587,237 ops/sec ±1.16% (187 runs sampled)
+  unquote     x 2,954,618 ops/sec ±1.35% (183 runs sampled)
+  duplicates  x   857,008 ops/sec ±0.89% (187 runs sampled)
+  10 cookies  x   292,133 ops/sec ±0.89% (187 runs sampled)
+  100 cookies x    22,610 ops/sec ±0.68% (187 runs sampled)
 ```
 
 ## References
@@ -275,6 +289,7 @@ $ npm run bench
 - [RFC 6265: HTTP State Management Mechanism][rfc-6265]
 - [Same-site Cookies][rfc-6265bis-09-5.4.7]
 
+[rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/
 [rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1
 [rfc-6265bis-09-5.4.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7
 [rfc-6265]: https://tools.ietf.org/html/rfc6265
@@ -291,12 +306,12 @@ $ npm run bench
 
 [MIT](LICENSE)
 
+[ci-image]: https://badgen.net/github/checks/jshttp/cookie/master?label=ci
+[ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml
 [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master
 [coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master
-[github-actions-ci-image]: https://img.shields.io/github/workflow/status/jshttp/cookie/ci/master?label=ci
-[github-actions-ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml
-[node-version-image]: https://badgen.net/npm/node/cookie
-[node-version-url]: https://nodejs.org/en/download
+[node-image]: https://badgen.net/npm/node/cookie
+[node-url]: https://nodejs.org/en/download
 [npm-downloads-image]: https://badgen.net/npm/dm/cookie
 [npm-url]: https://npmjs.org/package/cookie
 [npm-version-image]: https://badgen.net/npm/v/cookie

+ 121 - 57
express-server/node_modules/cookie/index.js

@@ -23,14 +23,66 @@ exports.serialize = serialize;
 var __toString = Object.prototype.toString
 
 /**
- * RegExp to match field-content in RFC 7230 sec 3.2
+ * RegExp to match cookie-name in RFC 6265 sec 4.1.1
+ * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
+ * which has been replaced by the token definition in RFC 7230 appendix B.
  *
- * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
- * field-vchar   = VCHAR / obs-text
- * obs-text      = %x80-FF
+ * cookie-name       = token
+ * token             = 1*tchar
+ * tchar             = "!" / "#" / "$" / "%" / "&" / "'" /
+ *                     "*" / "+" / "-" / "." / "^" / "_" /
+ *                     "`" / "|" / "~" / DIGIT / ALPHA
  */
 
-var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
+var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
+
+/**
+ * RegExp to match cookie-value in RFC 6265 sec 4.1.1
+ *
+ * cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
+ * cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
+ *                     ; US-ASCII characters excluding CTLs,
+ *                     ; whitespace DQUOTE, comma, semicolon,
+ *                     ; and backslash
+ */
+
+var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
+
+/**
+ * RegExp to match domain-value in RFC 6265 sec 4.1.1
+ *
+ * domain-value      = <subdomain>
+ *                     ; defined in [RFC1034], Section 3.5, as
+ *                     ; enhanced by [RFC1123], Section 2.1
+ * <subdomain>       = <label> | <subdomain> "." <label>
+ * <label>           = <let-dig> [ [ <ldh-str> ] <let-dig> ]
+ *                     Labels must be 63 characters or less.
+ *                     'let-dig' not 'letter' in the first char, per RFC1123
+ * <ldh-str>         = <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+ * <let-dig-hyp>     = <let-dig> | "-"
+ * <let-dig>         = <letter> | <digit>
+ * <letter>          = any one of the 52 alphabetic characters A through Z in
+ *                     upper case and a through z in lower case
+ * <digit>           = any one of the ten digits 0 through 9
+ *
+ * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173
+ *
+ * > (Note that a leading %x2E ("."), if present, is ignored even though that
+ * character is not permitted, but a trailing %x2E ("."), if present, will
+ * cause the user agent to ignore the attribute.)
+ */
+
+var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
+
+/**
+ * RegExp to match path-value in RFC 6265 sec 4.1.1
+ *
+ * path-value        = <any CHAR except CTLs or ";">
+ * CHAR              = %x01-7F
+ *                     ; defined in RFC 5234 appendix B.1
+ */
+
+var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
 
 /**
  * Parse a cookie header.
@@ -39,107 +91,128 @@ var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
  * The object has the various cookies as keys(names) => values
  *
  * @param {string} str
- * @param {object} [options]
+ * @param {object} [opt]
  * @return {object}
  * @public
  */
 
-function parse(str, options) {
+function parse(str, opt) {
   if (typeof str !== 'string') {
     throw new TypeError('argument str must be a string');
   }
 
-  var obj = {}
-  var opt = options || {};
-  var dec = opt.decode || decode;
+  var obj = {};
+  var len = str.length;
+  // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.
+  if (len < 2) return obj;
 
-  var index = 0
-  while (index < str.length) {
-    var eqIdx = str.indexOf('=', index)
+  var dec = (opt && opt.decode) || decode;
+  var index = 0;
+  var eqIdx = 0;
+  var endIdx = 0;
 
-    // no more cookie pairs
-    if (eqIdx === -1) {
-      break
-    }
+  do {
+    eqIdx = str.indexOf('=', index);
+    if (eqIdx === -1) break; // No more cookie pairs.
 
-    var endIdx = str.indexOf(';', index)
+    endIdx = str.indexOf(';', index);
 
     if (endIdx === -1) {
-      endIdx = str.length
-    } else if (endIdx < eqIdx) {
+      endIdx = len;
+    } else if (eqIdx > endIdx) {
       // backtrack on prior semicolon
-      index = str.lastIndexOf(';', eqIdx - 1) + 1
-      continue
+      index = str.lastIndexOf(';', eqIdx - 1) + 1;
+      continue;
     }
 
-    var key = str.slice(index, eqIdx).trim()
+    var keyStartIdx = startIndex(str, index, eqIdx);
+    var keyEndIdx = endIndex(str, eqIdx, keyStartIdx);
+    var key = str.slice(keyStartIdx, keyEndIdx);
 
     // only assign once
-    if (undefined === obj[key]) {
-      var val = str.slice(eqIdx + 1, endIdx).trim()
+    if (!obj.hasOwnProperty(key)) {
+      var valStartIdx = startIndex(str, eqIdx + 1, endIdx);
+      var valEndIdx = endIndex(str, endIdx, valStartIdx);
 
-      // quoted values
-      if (val.charCodeAt(0) === 0x22) {
-        val = val.slice(1, -1)
+      if (str.charCodeAt(valStartIdx) === 0x22 /* " */ && str.charCodeAt(valEndIdx - 1) === 0x22 /* " */) {
+        valStartIdx++;
+        valEndIdx--;
       }
 
+      var val = str.slice(valStartIdx, valEndIdx);
       obj[key] = tryDecode(val, dec);
     }
 
     index = endIdx + 1
-  }
+  } while (index < len);
 
   return obj;
 }
 
+function startIndex(str, index, max) {
+  do {
+    var code = str.charCodeAt(index);
+    if (code !== 0x20 /*   */ && code !== 0x09 /* \t */) return index;
+  } while (++index < max);
+  return max;
+}
+
+function endIndex(str, index, min) {
+  while (index > min) {
+    var code = str.charCodeAt(--index);
+    if (code !== 0x20 /*   */ && code !== 0x09 /* \t */) return index + 1;
+  }
+  return min;
+}
+
 /**
  * Serialize data into a cookie header.
  *
- * Serialize the a name value pair into a cookie string suitable for
- * http headers. An optional options object specified cookie parameters.
+ * Serialize a name value pair into a cookie string suitable for
+ * http headers. An optional options object specifies cookie parameters.
  *
  * serialize('foo', 'bar', { httpOnly: true })
  *   => "foo=bar; httpOnly"
  *
  * @param {string} name
  * @param {string} val
- * @param {object} [options]
+ * @param {object} [opt]
  * @return {string}
  * @public
  */
 
-function serialize(name, val, options) {
-  var opt = options || {};
-  var enc = opt.encode || encode;
+function serialize(name, val, opt) {
+  var enc = (opt && opt.encode) || encodeURIComponent;
 
   if (typeof enc !== 'function') {
     throw new TypeError('option encode is invalid');
   }
 
-  if (!fieldContentRegExp.test(name)) {
+  if (!cookieNameRegExp.test(name)) {
     throw new TypeError('argument name is invalid');
   }
 
   var value = enc(val);
 
-  if (value && !fieldContentRegExp.test(value)) {
+  if (!cookieValueRegExp.test(value)) {
     throw new TypeError('argument val is invalid');
   }
 
   var str = name + '=' + value;
+  if (!opt) return str;
 
   if (null != opt.maxAge) {
-    var maxAge = opt.maxAge - 0;
+    var maxAge = Math.floor(opt.maxAge);
 
-    if (isNaN(maxAge) || !isFinite(maxAge)) {
+    if (!isFinite(maxAge)) {
       throw new TypeError('option maxAge is invalid')
     }
 
-    str += '; Max-Age=' + Math.floor(maxAge);
+    str += '; Max-Age=' + maxAge;
   }
 
   if (opt.domain) {
-    if (!fieldContentRegExp.test(opt.domain)) {
+    if (!domainValueRegExp.test(opt.domain)) {
       throw new TypeError('option domain is invalid');
     }
 
@@ -147,7 +220,7 @@ function serialize(name, val, options) {
   }
 
   if (opt.path) {
-    if (!fieldContentRegExp.test(opt.path)) {
+    if (!pathValueRegExp.test(opt.path)) {
       throw new TypeError('option path is invalid');
     }
 
@@ -172,10 +245,13 @@ function serialize(name, val, options) {
     str += '; Secure';
   }
 
+  if (opt.partitioned) {
+    str += '; Partitioned'
+  }
+
   if (opt.priority) {
     var priority = typeof opt.priority === 'string'
-      ? opt.priority.toLowerCase()
-      : opt.priority
+      ? opt.priority.toLowerCase() : opt.priority;
 
     switch (priority) {
       case 'low':
@@ -230,17 +306,6 @@ function decode (str) {
     : str
 }
 
-/**
- * URL-encode value.
- *
- * @param {string} str
- * @returns {string}
- */
-
-function encode (val) {
-  return encodeURIComponent(val)
-}
-
 /**
  * Determine if value is a Date.
  *
@@ -249,8 +314,7 @@ function encode (val) {
  */
 
 function isDate (val) {
-  return __toString.call(val) === '[object Date]' ||
-    val instanceof Date
+  return __toString.call(val) === '[object Date]';
 }
 
 /**

+ 16 - 16
express-server/node_modules/cookie/package.json

@@ -1,26 +1,26 @@
 {
-  "_from": "cookie@0.5.0",
-  "_id": "cookie@0.5.0",
+  "_from": "cookie@0.7.1",
+  "_id": "cookie@0.7.1",
   "_inBundle": false,
-  "_integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+  "_integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
   "_location": "/cookie",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "cookie@0.5.0",
+    "raw": "cookie@0.7.1",
     "name": "cookie",
     "escapedName": "cookie",
-    "rawSpec": "0.5.0",
+    "rawSpec": "0.7.1",
     "saveSpec": null,
-    "fetchSpec": "0.5.0"
+    "fetchSpec": "0.7.1"
   },
   "_requiredBy": [
     "/express"
   ],
-  "_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
-  "_shasum": "d1f5d71adec6558c58f389987c366aa47e994f8b",
-  "_spec": "cookie@0.5.0",
+  "_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+  "_shasum": "2f73c42142d5d5cf71310a74fc4ae61670e5dbc9",
+  "_spec": "cookie@0.7.1",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "author": {
     "name": "Roman Shtylman",
@@ -41,12 +41,12 @@
   "devDependencies": {
     "beautify-benchmark": "0.2.4",
     "benchmark": "2.1.4",
-    "eslint": "7.32.0",
-    "eslint-plugin-markdown": "2.2.1",
-    "mocha": "9.2.2",
+    "eslint": "8.53.0",
+    "eslint-plugin-markdown": "3.0.1",
+    "mocha": "10.2.0",
     "nyc": "15.1.0",
     "safe-buffer": "5.2.1",
-    "top-sites": "1.1.97"
+    "top-sites": "1.1.194"
   },
   "engines": {
     "node": ">= 0.6"
@@ -64,6 +64,7 @@
     "cookies"
   ],
   "license": "MIT",
+  "main": "index.js",
   "name": "cookie",
   "repository": {
     "type": "git",
@@ -75,8 +76,7 @@
     "test": "mocha --reporter spec --bail --check-leaks test/",
     "test-ci": "nyc --reporter=lcov --reporter=text npm test",
     "test-cov": "nyc --reporter=html --reporter=text npm test",
-    "update-bench": "node scripts/update-benchmark.js",
-    "version": "node scripts/version-history.js && git add HISTORY.md"
+    "update-bench": "node scripts/update-benchmark.js"
   },
-  "version": "0.5.0"
+  "version": "0.7.1"
 }

+ 4 - 0
express-server/node_modules/debug/package.json

@@ -18,8 +18,12 @@
   "_requiredBy": [
     "/body-parser",
     "/express",
+    "/express-session",
     "/finalhandler",
     "/get-uri",
+    "/http-proxy-agent",
+    "/pac-proxy-agent",
+    "/proxy-agent/https-proxy-agent",
     "/send"
   ],
   "_resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",

+ 1 - 0
express-server/node_modules/depd/package.json

@@ -18,6 +18,7 @@
   "_requiredBy": [
     "/body-parser",
     "/express",
+    "/express-session",
     "/http-errors",
     "/send"
   ],

+ 16 - 17
express-server/node_modules/encodeurl/package.json

@@ -1,29 +1,28 @@
 {
-  "_from": "encodeurl@~1.0.2",
-  "_id": "encodeurl@1.0.2",
+  "_from": "encodeurl@~2.0.0",
+  "_id": "encodeurl@2.0.0",
   "_inBundle": false,
-  "_integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+  "_integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
   "_location": "/encodeurl",
   "_phantomChildren": {},
   "_requested": {
     "type": "range",
     "registry": true,
-    "raw": "encodeurl@~1.0.2",
+    "raw": "encodeurl@~2.0.0",
     "name": "encodeurl",
     "escapedName": "encodeurl",
-    "rawSpec": "~1.0.2",
+    "rawSpec": "~2.0.0",
     "saveSpec": null,
-    "fetchSpec": "~1.0.2"
+    "fetchSpec": "~2.0.0"
   },
   "_requiredBy": [
     "/express",
     "/finalhandler",
-    "/send",
     "/serve-static"
   ],
-  "_resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-  "_shasum": "ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59",
-  "_spec": "encodeurl@~1.0.2",
+  "_resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+  "_shasum": "7b8ea898077d7e409d3ac45474ea38eaf0857a58",
+  "_spec": "encodeurl@~2.0.0",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "bugs": {
     "url": "https://github.com/pillarjs/encodeurl/issues"
@@ -38,12 +37,12 @@
   "deprecated": false,
   "description": "Encode a URL to a percent-encoded form, excluding already-encoded sequences",
   "devDependencies": {
-    "eslint": "3.19.0",
-    "eslint-config-standard": "10.2.1",
-    "eslint-plugin-import": "2.8.0",
-    "eslint-plugin-node": "5.2.1",
-    "eslint-plugin-promise": "3.6.0",
-    "eslint-plugin-standard": "3.0.1",
+    "eslint": "5.11.1",
+    "eslint-config-standard": "12.0.0",
+    "eslint-plugin-import": "2.14.0",
+    "eslint-plugin-node": "7.0.1",
+    "eslint-plugin-promise": "4.0.1",
+    "eslint-plugin-standard": "4.0.0",
     "istanbul": "0.4.5",
     "mocha": "2.5.3"
   },
@@ -74,5 +73,5 @@
     "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
     "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
   },
-  "version": "1.0.2"
+  "version": "2.0.0"
 }

+ 82 - 5
express-server/node_modules/express/History.md

@@ -1,3 +1,80 @@
+4.21.2 / 2024-11-06
+==========
+
+  * deps: path-to-regexp@0.1.12
+    - Fix backtracking protection
+  * deps: path-to-regexp@0.1.11
+    - Throws an error on invalid path values
+
+4.21.1 / 2024-10-08
+==========
+
+  * Backported a fix for [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764)
+
+
+4.21.0 / 2024-09-11
+==========
+
+  * Deprecate `res.location("back")` and `res.redirect("back")` magic string
+  * deps: serve-static@1.16.2
+    * includes send@0.19.0
+  * deps: finalhandler@1.3.1
+  * deps: qs@6.13.0
+
+4.20.0 / 2024-09-10
+==========
+  * deps: serve-static@0.16.0
+    * Remove link renderization in html while redirecting
+  * deps: send@0.19.0
+    * Remove link renderization in html while redirecting
+  * deps: body-parser@0.6.0
+    * add `depth` option to customize the depth level in the parser
+    * IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
+  * Remove link renderization in html while using `res.redirect`
+  * deps: path-to-regexp@0.1.10
+    - Adds support for named matching groups in the routes using a regex
+    - Adds backtracking protection to parameters without regexes defined
+  * deps: encodeurl@~2.0.0
+    - Removes encoding of `\`, `|`, and `^` to align better with URL spec
+  * Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`
+    - Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie
+
+4.19.2 / 2024-03-25
+==========
+
+  * Improved fix for open redirect allow list bypass
+
+4.19.1 / 2024-03-20
+==========
+
+  * Allow passing non-strings to res.location with new encoding handling checks
+
+4.19.0 / 2024-03-20
+==========
+
+  * Prevent open redirect allow list bypass due to encodeurl
+  * deps: cookie@0.6.0
+
+4.18.3 / 2024-02-29
+==========
+
+  * Fix routing requests without method
+  * deps: body-parser@1.20.2
+    - Fix strict json error message on Node.js 19+
+    - deps: content-type@~1.0.5
+    - deps: raw-body@2.5.2
+  * deps: cookie@0.6.0
+    - Add `partitioned` option
+
+4.18.2 / 2022-10-08
+===================
+
+  * Fix regression routing a large stack in a single route
+  * deps: body-parser@1.20.1
+    - deps: qs@6.11.0
+    - perf: remove unnecessary object clone
+  * deps: qs@6.11.0
+
 4.18.1 / 2022-04-29
 ===================
 
@@ -2102,7 +2179,7 @@
  * deps: connect@2.21.0
    - deprecate `connect(middleware)` -- use `app.use(middleware)` instead
    - deprecate `connect.createServer()` -- use `connect()` instead
-   - fix `res.setHeader()` patch to work with with get -> append -> set pattern
+   - fix `res.setHeader()` patch to work with get -> append -> set pattern
    - deps: compression@~1.0.8
    - deps: errorhandler@~1.1.1
    - deps: express-session@~1.5.0
@@ -3313,8 +3390,8 @@ Shaw]
   * Added node v0.1.97 compatibility
   * Added support for deleting cookies via Request#cookie('key', null)
   * Updated haml submodule
-  * Fixed not-found page, now using using charset utf-8
-  * Fixed show-exceptions page, now using using charset utf-8
+  * Fixed not-found page, now using charset utf-8
+  * Fixed show-exceptions page, now using charset utf-8
   * Fixed view support due to fs.readFile Buffers
   * Changed; mime.type() no longer accepts ".type" due to node extname() changes
 
@@ -3349,7 +3426,7 @@ Shaw]
 ==================
 
   * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s
-    encoding is set to 'utf8' or 'utf-8'.
+    encoding is set to 'utf8' or 'utf-8').
   * Added "encoding" option to Request#render(). Closes #299
   * Added "dump exceptions" setting, which is enabled by default.
   * Added simple ejs template engine support
@@ -3388,7 +3465,7 @@ Shaw]
   * Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js
   * Added callback function support to Request#halt() as 3rd/4th arg
   * Added preprocessing of route param wildcards using param(). Closes #251
-  * Added view partial support (with collections etc)
+  * Added view partial support (with collections etc.)
   * Fixed bug preventing falsey params (such as ?page=0). Closes #286
   * Fixed setting of multiple cookies. Closes #199
   * Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)

+ 102 - 8
express-server/node_modules/express/Readme.md

@@ -1,10 +1,29 @@
 [![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)
 
-  Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
+**Fast, unopinionated, minimalist web framework for [Node.js](http://nodejs.org).**
+
+**This project has a [Code of Conduct][].**
+
+## Table of contents
+
+* [Installation](#Installation)
+* [Features](#Features)
+* [Docs & Community](#docs--community)
+* [Quick Start](#Quick-Start)
+* [Running Tests](#Running-Tests)
+* [Philosophy](#Philosophy)
+* [Examples](#Examples)
+* [Contributing to Express](#Contributing)
+* [TC (Technical Committee)](#tc-technical-committee)
+* [Triagers](#triagers)
+* [License](#license)
+
+
+[![NPM Version][npm-version-image]][npm-url]
+[![NPM Install Size][npm-install-size-image]][npm-install-size-url]
+[![NPM Downloads][npm-downloads-image]][npm-downloads-url]
+[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
 
-  [![NPM Version][npm-version-image]][npm-url]
-  [![NPM Install Size][npm-install-size-image]][npm-install-size-url]
-  [![NPM Downloads][npm-downloads-image]][npm-downloads-url]
 
 ```js
 const express = require('express')
@@ -51,7 +70,7 @@ for more information.
 ## Docs & Community
 
   * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
-  * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
+  * [#express](https://web.libera.chat/#express) on [Libera Chat](https://libera.chat) IRC
   * [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
   * Visit the [Wiki](https://github.com/expressjs/express/wiki)
   * [Google Group](https://groups.google.com/group/express-js) for discussion
@@ -104,7 +123,7 @@ $ npm start
   To view the examples, clone the Express repo and install the dependencies:
 
 ```console
-$ git clone git://github.com/expressjs/express.git --depth 1
+$ git clone https://github.com/expressjs/express.git --depth 1
 $ cd express
 $ npm install
 ```
@@ -144,10 +163,82 @@ $ npm test
 
 The original author of Express is [TJ Holowaychuk](https://github.com/tj)
 
-The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson)
-
 [List of all contributors](https://github.com/expressjs/express/graphs/contributors)
 
+### TC (Technical Committee)
+
+* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
+* [jonchurch](https://github.com/jonchurch) - **Jon Church**
+* [wesleytodd](https://github.com/wesleytodd) - **Wes Todd**
+* [LinusU](https://github.com/LinusU) - **Linus Unnebäck**
+* [blakeembrey](https://github.com/blakeembrey) - **Blake Embrey**
+* [sheplu](https://github.com/sheplu) - **Jean Burellier**
+* [crandmck](https://github.com/crandmck) - **Rand McKinney**
+* [ctcpip](https://github.com/ctcpip) - **Chris de Almeida**
+
+<details>
+<summary>TC emeriti members</summary>
+
+#### TC emeriti members
+
+  * [dougwilson](https://github.com/dougwilson) - **Douglas Wilson**
+  * [hacksparrow](https://github.com/hacksparrow) - **Hage Yaapa**
+  * [jonathanong](https://github.com/jonathanong) - **jongleberry**
+  * [niftylettuce](https://github.com/niftylettuce) - **niftylettuce**
+  * [troygoode](https://github.com/troygoode) - **Troy Goode**
+</details>
+
+
+### Triagers
+
+* [aravindvnair99](https://github.com/aravindvnair99) - **Aravind Nair**
+* [carpasse](https://github.com/carpasse) - **Carlos Serrano**
+* [CBID2](https://github.com/CBID2) - **Christine Belzie**
+* [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim**
+* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
+* [mertcanaltin](https://github.com/mertcanaltin) - **Mert Can Altin**
+* [0ss](https://github.com/0ss) - **Salah**
+* [import-brain](https://github.com/import-brain) - **Eric Cheng** (he/him)
+* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
+* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
+* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
+* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
+* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
+
+<details>
+<summary>Triagers emeriti members</summary>
+
+#### Emeritus Triagers
+
+  * [AuggieH](https://github.com/AuggieH) - **Auggie Hudak**
+  * [G-Rath](https://github.com/G-Rath) - **Gareth Jones**
+  * [MohammadXroid](https://github.com/MohammadXroid) - **Mohammad Ayashi**
+  * [NawafSwe](https://github.com/NawafSwe) - **Nawaf Alsharqi**
+  * [NotMoni](https://github.com/NotMoni) - **Moni**
+  * [VigneshMurugan](https://github.com/VigneshMurugan) - **Vignesh Murugan**
+  * [davidmashe](https://github.com/davidmashe) - **David Ashe**
+  * [digitaIfabric](https://github.com/digitaIfabric) - **David**
+  * [e-l-i-s-e](https://github.com/e-l-i-s-e) - **Elise Bonner**
+  * [fed135](https://github.com/fed135) - **Frederic Charette**
+  * [firmanJS](https://github.com/firmanJS) - **Firman Abdul Hakim**
+  * [getspooky](https://github.com/getspooky) - **Yasser Ameur**
+  * [ghinks](https://github.com/ghinks) - **Glenn**
+  * [ghousemohamed](https://github.com/ghousemohamed) - **Ghouse Mohamed**
+  * [gireeshpunathil](https://github.com/gireeshpunathil) - **Gireesh Punathil**
+  * [jake32321](https://github.com/jake32321) - **Jake Reed**
+  * [jonchurch](https://github.com/jonchurch) - **Jon Church**
+  * [lekanikotun](https://github.com/lekanikotun) - **Troy Goode**
+  * [marsonya](https://github.com/marsonya) - **Lekan Ikotun**
+  * [mastermatt](https://github.com/mastermatt) - **Matt R. Wilson**
+  * [maxakuru](https://github.com/maxakuru) - **Max Edell**
+  * [mlrawlings](https://github.com/mlrawlings) - **Michael Rawlings**
+  * [rodion-arr](https://github.com/rodion-arr) - **Rodion Abdurakhimov**
+  * [sheplu](https://github.com/sheplu) - **Jean Burellier**
+  * [tarunyadav1](https://github.com/tarunyadav1) - **Tarun yadav**
+  * [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe**
+</details>
+
+
 ## License
 
   [MIT](LICENSE)
@@ -164,3 +255,6 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d
 [npm-install-size-url]: https://packagephobia.com/result?p=express
 [npm-url]: https://npmjs.org/package/express
 [npm-version-image]: https://badgen.net/npm/v/express
+[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
+[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express
+[Code of Conduct]: https://github.com/expressjs/express/blob/master/Code-Of-Conduct.md

+ 13 - 3
express-server/node_modules/express/lib/response.js

@@ -822,6 +822,14 @@ res.get = function(field){
  */
 
 res.clearCookie = function clearCookie(name, options) {
+  if (options) {
+    if (options.maxAge) {
+      deprecate('res.clearCookie: Passing "options.maxAge" is deprecated. In v5.0.0 of Express, this option will be ignored, as res.clearCookie will automatically set cookies to expire immediately. Please update your code to omit this option.');
+    }
+    if (options.expires) {
+      deprecate('res.clearCookie: Passing "options.expires" is deprecated. In v5.0.0 of Express, this option will be ignored, as res.clearCookie will automatically set cookies to expire immediately. Please update your code to omit this option.');
+    }
+  }
   var opts = merge({ expires: new Date(1), path: '/' }, options);
 
   return this.cookie(name, '', opts);
@@ -904,14 +912,16 @@ res.cookie = function (name, value, options) {
  */
 
 res.location = function location(url) {
-  var loc = url;
+  var loc;
 
   // "back" is an alias for the referrer
   if (url === 'back') {
+    deprecate('res.location("back"): use res.location(req.get("Referrer") || "/") and refer to https://dub.sh/security-redirect for best practices');
     loc = this.req.get('Referrer') || '/';
+  } else {
+    loc = String(url);
   }
 
-  // set location
   return this.set('Location', encodeUrl(loc));
 };
 
@@ -960,7 +970,7 @@ res.redirect = function redirect(url) {
 
     html: function(){
       var u = escapeHtml(address);
-      body = '<p>' + statuses.message[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>'
+      body = '<p>' + statuses.message[status] + '. Redirecting to ' + u + '</p>'
     },
 
     default: function(){

+ 1 - 1
express-server/node_modules/express/lib/router/index.js

@@ -36,7 +36,7 @@ var toString = Object.prototype.toString;
  * Initialize a new `Router` with the given `options`.
  *
  * @param {Object} [options]
- * @return {Router} which is an callable function
+ * @return {Router} which is a callable function
  * @public
  */
 

+ 15 - 10
express-server/node_modules/express/lib/router/route.js

@@ -60,7 +60,10 @@ Route.prototype._handles_method = function _handles_method(method) {
     return true;
   }
 
-  var name = method.toLowerCase();
+  // normalize name
+  var name = typeof method === 'string'
+    ? method.toLowerCase()
+    : method
 
   if (name === 'head' && !this.methods['head']) {
     name = 'get';
@@ -103,8 +106,10 @@ Route.prototype.dispatch = function dispatch(req, res, done) {
   if (stack.length === 0) {
     return done();
   }
+  var method = typeof req.method === 'string'
+    ? req.method.toLowerCase()
+    : req.method
 
-  var method = req.method.toLowerCase();
   if (method === 'head' && !this.methods['head']) {
     method = 'get';
   }
@@ -124,21 +129,21 @@ Route.prototype.dispatch = function dispatch(req, res, done) {
       return done(err)
     }
 
-    var layer = stack[idx++];
-    if (!layer) {
-      return done(err);
-    }
-
     // max sync stack
     if (++sync > 100) {
       return setImmediate(next, err)
     }
 
-    if (layer.method && layer.method !== method) {
-      return next(err);
+    var layer = stack[idx++]
+
+    // end of layers
+    if (!layer) {
+      return done(err)
     }
 
-    if (err) {
+    if (layer.method && layer.method !== method) {
+      next(err)
+    } else if (err) {
       layer.handle_error(err, req, res, next);
     } else {
       layer.handle_request(req, res, next);

+ 3 - 4
express-server/node_modules/express/lib/utils.js

@@ -117,17 +117,15 @@ exports.contentDisposition = deprecate.function(contentDisposition,
 /**
  * Parse accept params `str` returning an
  * object with `.value`, `.quality` and `.params`.
- * also includes `.originalIndex` for stable sorting
  *
  * @param {String} str
- * @param {Number} index
  * @return {Object}
  * @api private
  */
 
-function acceptParams(str, index) {
+function acceptParams (str) {
   var parts = str.split(/ *; */);
-  var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index };
+  var ret = { value: parts[0], quality: 1, params: {} }
 
   for (var i = 1; i < parts.length; ++i) {
     var pms = parts[i].split(/ *= */);
@@ -282,6 +280,7 @@ function createETagGenerator (options) {
 /**
  * Parse an extended query string with qs.
  *
+ * @param {String} str
  * @return {Object}
  * @private
  */

+ 24 - 21
express-server/node_modules/express/package.json

@@ -1,8 +1,8 @@
 {
   "_from": "express@^4.17.1",
-  "_id": "express@4.18.1",
+  "_id": "express@4.21.2",
   "_inBundle": false,
-  "_integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==",
+  "_integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
   "_location": "/express",
   "_phantomChildren": {},
   "_requested": {
@@ -19,8 +19,8 @@
     "/",
     "/api-express-exporter"
   ],
-  "_resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz",
-  "_shasum": "7797de8b9c72c857b9cd0e14a5eea80666267caf",
+  "_resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+  "_shasum": "cf250e48362174ead6cea4a566abef0162c1ec32",
   "_spec": "express@^4.17.1",
   "_where": "C:\\FatboarProject\\express-server",
   "author": {
@@ -64,30 +64,30 @@
   "dependencies": {
     "accepts": "~1.3.8",
     "array-flatten": "1.1.1",
-    "body-parser": "1.20.0",
+    "body-parser": "1.20.3",
     "content-disposition": "0.5.4",
     "content-type": "~1.0.4",
-    "cookie": "0.5.0",
+    "cookie": "0.7.1",
     "cookie-signature": "1.0.6",
     "debug": "2.6.9",
     "depd": "2.0.0",
-    "encodeurl": "~1.0.2",
+    "encodeurl": "~2.0.0",
     "escape-html": "~1.0.3",
     "etag": "~1.8.1",
-    "finalhandler": "1.2.0",
+    "finalhandler": "1.3.1",
     "fresh": "0.5.2",
     "http-errors": "2.0.0",
-    "merge-descriptors": "1.0.1",
+    "merge-descriptors": "1.0.3",
     "methods": "~1.1.2",
     "on-finished": "2.4.1",
     "parseurl": "~1.3.3",
-    "path-to-regexp": "0.1.7",
+    "path-to-regexp": "0.1.12",
     "proxy-addr": "~2.0.7",
-    "qs": "6.10.3",
+    "qs": "6.13.0",
     "range-parser": "~1.2.1",
     "safe-buffer": "5.2.1",
-    "send": "0.18.0",
-    "serve-static": "1.15.0",
+    "send": "0.19.0",
+    "serve-static": "1.16.2",
     "setprototypeof": "1.2.0",
     "statuses": "2.0.1",
     "type-is": "~1.6.18",
@@ -101,18 +101,17 @@
     "connect-redis": "3.4.2",
     "cookie-parser": "1.4.6",
     "cookie-session": "2.0.0",
-    "ejs": "3.1.7",
-    "eslint": "7.32.0",
+    "ejs": "3.1.9",
+    "eslint": "8.47.0",
     "express-session": "1.17.2",
     "hbs": "4.2.0",
     "marked": "0.7.0",
     "method-override": "3.0.0",
-    "mocha": "9.2.2",
+    "mocha": "10.2.0",
     "morgan": "1.10.0",
-    "multiparty": "4.2.3",
     "nyc": "15.1.0",
     "pbkdf2-password": "1.2.1",
-    "supertest": "6.2.3",
+    "supertest": "6.3.0",
     "vhost": "~3.0.2"
   },
   "engines": {
@@ -125,6 +124,10 @@
     "index.js",
     "lib/"
   ],
+  "funding": {
+    "type": "opencollective",
+    "url": "https://opencollective.com/express"
+  },
   "homepage": "http://expressjs.com/",
   "keywords": [
     "express",
@@ -147,9 +150,9 @@
   "scripts": {
     "lint": "eslint .",
     "test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
-    "test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
-    "test-cov": "nyc --reporter=html --reporter=text npm test",
+    "test-ci": "nyc --exclude examples --exclude test --exclude benchmarks --reporter=lcovonly --reporter=text npm test",
+    "test-cov": "nyc --exclude examples --exclude test --exclude benchmarks --reporter=html --reporter=text npm test",
     "test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
   },
-  "version": "4.18.1"
+  "version": "4.21.2"
 }

+ 15 - 0
express-server/node_modules/finalhandler/HISTORY.md

@@ -1,3 +1,18 @@
+v1.3.1 / 2024-09-11
+==================
+
+  * deps: encodeurl@~2.0.0
+
+v1.3.0 / 2024-09-03
+==================
+
+  * ignore status message for HTTP/2 (#53)
+
+v1.2.1 / 2024-09-02
+==================
+
+  * Gracefully handle when handling an error and socket is null
+
 1.2.0 / 2022-03-22
 ==================
 

+ 2 - 2
express-server/node_modules/finalhandler/README.md

@@ -143,5 +143,5 @@ function logerror (err) {
 [coveralls-url]: https://coveralls.io/r/pillarjs/finalhandler?branch=master
 [downloads-image]: https://img.shields.io/npm/dm/finalhandler.svg
 [downloads-url]: https://npmjs.org/package/finalhandler
-[github-actions-ci-image]: https://img.shields.io/github/workflow/status/pillarjs/finalhandler/ci/master?label=ci
-[github-actions-ci-url]: https://github.com/jshttp/pillarjs/finalhandler?query=workflow%3Aci
+[github-actions-ci-image]: https://github.com/pillarjs/finalhandler/actions/workflows/ci.yml/badge.svg
+[github-actions-ci-url]: https://github.com/pillarjs/finalhandler/actions/workflows/ci.yml

+ 7 - 2
express-server/node_modules/finalhandler/index.js

@@ -125,7 +125,9 @@ function finalhandler (req, res, options) {
     // cannot actually respond
     if (headersSent(res)) {
       debug('cannot %d after headers sent', status)
-      req.socket.destroy()
+      if (req.socket) {
+        req.socket.destroy()
+      }
       return
     }
 
@@ -276,7 +278,10 @@ function send (req, res, status, headers, message) {
 
     // response status
     res.statusCode = status
-    res.statusMessage = statuses.message[status]
+
+    if (req.httpVersionMajor < 2) {
+      res.statusMessage = statuses.message[status]
+    }
 
     // remove any content headers
     res.removeHeader('Content-Encoding')

+ 17 - 16
express-server/node_modules/finalhandler/package.json

@@ -1,26 +1,26 @@
 {
-  "_from": "finalhandler@1.2.0",
-  "_id": "finalhandler@1.2.0",
+  "_from": "finalhandler@1.3.1",
+  "_id": "finalhandler@1.3.1",
   "_inBundle": false,
-  "_integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+  "_integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
   "_location": "/finalhandler",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "finalhandler@1.2.0",
+    "raw": "finalhandler@1.3.1",
     "name": "finalhandler",
     "escapedName": "finalhandler",
-    "rawSpec": "1.2.0",
+    "rawSpec": "1.3.1",
     "saveSpec": null,
-    "fetchSpec": "1.2.0"
+    "fetchSpec": "1.3.1"
   },
   "_requiredBy": [
     "/express"
   ],
-  "_resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
-  "_shasum": "7d23fe5731b207b4640e4fcd00aec1f9207a7b32",
-  "_spec": "finalhandler@1.2.0",
+  "_resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+  "_shasum": "0c575f1d1d324ddd1da35ad7ece3df7d19088019",
+  "_spec": "finalhandler@1.3.1",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "author": {
     "name": "Douglas Christopher Wilson",
@@ -32,7 +32,7 @@
   "bundleDependencies": false,
   "dependencies": {
     "debug": "2.6.9",
-    "encodeurl": "~1.0.2",
+    "encodeurl": "~2.0.0",
     "escape-html": "~1.0.3",
     "on-finished": "2.4.1",
     "parseurl": "~1.3.3",
@@ -44,16 +44,16 @@
   "devDependencies": {
     "eslint": "7.32.0",
     "eslint-config-standard": "14.1.1",
-    "eslint-plugin-import": "2.25.4",
+    "eslint-plugin-import": "2.26.0",
     "eslint-plugin-markdown": "2.2.1",
     "eslint-plugin-node": "11.1.0",
     "eslint-plugin-promise": "5.2.0",
     "eslint-plugin-standard": "4.1.0",
-    "mocha": "9.2.2",
+    "mocha": "10.0.0",
     "nyc": "15.1.0",
     "readable-stream": "2.3.6",
     "safe-buffer": "5.2.1",
-    "supertest": "6.2.2"
+    "supertest": "6.2.4"
   },
   "engines": {
     "node": ">= 0.8"
@@ -73,9 +73,10 @@
   },
   "scripts": {
     "lint": "eslint .",
-    "test": "mocha --reporter spec --bail --check-leaks test/",
+    "test": "mocha --reporter spec --check-leaks test/",
     "test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
-    "test-cov": "nyc --reporter=html --reporter=text npm test"
+    "test-cov": "nyc --reporter=html --reporter=text npm test",
+    "test-inspect": "mocha --reporter spec --inspect --inspect-brk test/"
   },
-  "version": "1.2.0"
+  "version": "1.3.1"
 }

+ 1 - 1
express-server/node_modules/iconv-lite/package.json

@@ -17,7 +17,7 @@
   },
   "_requiredBy": [
     "/body-parser",
-    "/needle",
+    "/commoner",
     "/raw-body"
   ],
   "_resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",

+ 2 - 0
express-server/node_modules/inherits/package.json

@@ -16,7 +16,9 @@
     "fetchSpec": "2.0.4"
   },
   "_requiredBy": [
+    "/commoner/glob",
     "/ftp/readable-stream",
+    "/get-uri/readable-stream",
     "/glob",
     "/http-errors",
     "/readable-stream"

+ 25 - 18
express-server/node_modules/merge-descriptors/package.json

@@ -1,26 +1,26 @@
 {
-  "_from": "merge-descriptors@1.0.1",
-  "_id": "merge-descriptors@1.0.1",
+  "_from": "merge-descriptors@1.0.3",
+  "_id": "merge-descriptors@1.0.3",
   "_inBundle": false,
-  "_integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
+  "_integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
   "_location": "/merge-descriptors",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "merge-descriptors@1.0.1",
+    "raw": "merge-descriptors@1.0.3",
     "name": "merge-descriptors",
     "escapedName": "merge-descriptors",
-    "rawSpec": "1.0.1",
+    "rawSpec": "1.0.3",
     "saveSpec": null,
-    "fetchSpec": "1.0.1"
+    "fetchSpec": "1.0.3"
   },
   "_requiredBy": [
     "/express"
   ],
-  "_resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-  "_shasum": "b00aaa556dd8b44568150ec9d1b953f3f90cbb61",
-  "_spec": "merge-descriptors@1.0.1",
+  "_resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+  "_shasum": "d80319a65f3c7935351e5cfdac8f9318504dbed5",
+  "_spec": "merge-descriptors@1.0.3",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "author": {
     "name": "Jonathan Ong",
@@ -28,7 +28,7 @@
     "url": "http://jongleberry.com"
   },
   "bugs": {
-    "url": "https://github.com/component/merge-descriptors/issues"
+    "url": "https://github.com/sindresorhus/merge-descriptors/issues"
   },
   "bundleDependencies": false,
   "contributors": [
@@ -44,8 +44,14 @@
   "deprecated": false,
   "description": "Merge objects using descriptors",
   "devDependencies": {
-    "istanbul": "0.4.1",
-    "mocha": "1.21.5"
+    "eslint": "5.9.0",
+    "eslint-config-standard": "12.0.0",
+    "eslint-plugin-import": "2.14.0",
+    "eslint-plugin-node": "7.0.1",
+    "eslint-plugin-promise": "4.0.1",
+    "eslint-plugin-standard": "4.0.0",
+    "mocha": "5.2.0",
+    "nyc": "13.1.0"
   },
   "files": [
     "HISTORY.md",
@@ -53,17 +59,18 @@
     "README.md",
     "index.js"
   ],
-  "homepage": "https://github.com/component/merge-descriptors#readme",
+  "funding": "https://github.com/sponsors/sindresorhus",
+  "homepage": "https://github.com/sindresorhus/merge-descriptors#readme",
   "license": "MIT",
   "name": "merge-descriptors",
   "repository": {
     "type": "git",
-    "url": "git+https://github.com/component/merge-descriptors.git"
+    "url": "git+https://github.com/sindresorhus/merge-descriptors.git"
   },
   "scripts": {
-    "test": "mocha --reporter spec --bail --check-leaks test/",
-    "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
-    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
+    "lint": "eslint .",
+    "test": "mocha test/",
+    "test-cov": "nyc --reporter=html --reporter=text npm test"
   },
-  "version": "1.0.1"
+  "version": "1.0.3"
 }

+ 0 - 1
express-server/node_modules/mime-types/package.json

@@ -17,7 +17,6 @@
   },
   "_requiredBy": [
     "/accepts",
-    "/form-data",
     "/type-is"
   ],
   "_resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",

+ 2 - 1
express-server/node_modules/mkdirp/package.json

@@ -16,7 +16,8 @@
     "fetchSpec": "^1.0.4"
   },
   "_requiredBy": [
-    "/"
+    "/",
+    "/tar"
   ],
   "_resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
   "_shasum": "3eb5ed62622756d79a5f0e2a221dfebad75c2f7e",

+ 1 - 3
express-server/node_modules/ms/package.json

@@ -16,9 +16,7 @@
     "fetchSpec": "2.0.0"
   },
   "_requiredBy": [
-    "/debug",
-    "/http-proxy-agent/debug",
-    "/mquery/debug"
+    "/debug"
   ],
   "_resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
   "_shasum": "5608aeadfc00be6c2901df5f9861788de0d597c8",

+ 1 - 0
express-server/node_modules/parseurl/package.json

@@ -17,6 +17,7 @@
   },
   "_requiredBy": [
     "/express",
+    "/express-session",
     "/finalhandler",
     "/serve-static"
   ],

+ 13 - 13
express-server/node_modules/path-to-regexp/package.json

@@ -1,29 +1,29 @@
 {
-  "_from": "path-to-regexp@0.1.7",
-  "_id": "path-to-regexp@0.1.7",
+  "_from": "path-to-regexp@0.1.12",
+  "_id": "path-to-regexp@0.1.12",
   "_inBundle": false,
-  "_integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
+  "_integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
   "_location": "/path-to-regexp",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "path-to-regexp@0.1.7",
+    "raw": "path-to-regexp@0.1.12",
     "name": "path-to-regexp",
     "escapedName": "path-to-regexp",
-    "rawSpec": "0.1.7",
+    "rawSpec": "0.1.12",
     "saveSpec": null,
-    "fetchSpec": "0.1.7"
+    "fetchSpec": "0.1.12"
   },
   "_requiredBy": [
     "/express"
   ],
-  "_resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-  "_shasum": "df604178005f522f15eb4490e7247a1bfaa67f8c",
-  "_spec": "path-to-regexp@0.1.7",
+  "_resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+  "_shasum": "d5e1a12e478a976d432ef3c58d534b9923164bb7",
+  "_spec": "path-to-regexp@0.1.12",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "bugs": {
-    "url": "https://github.com/component/path-to-regexp/issues"
+    "url": "https://github.com/pillarjs/path-to-regexp/issues"
   },
   "bundleDependencies": false,
   "component": {
@@ -41,7 +41,7 @@
     "index.js",
     "LICENSE"
   ],
-  "homepage": "https://github.com/component/path-to-regexp#readme",
+  "homepage": "https://github.com/pillarjs/path-to-regexp#readme",
   "keywords": [
     "express",
     "regexp"
@@ -50,10 +50,10 @@
   "name": "path-to-regexp",
   "repository": {
     "type": "git",
-    "url": "git+https://github.com/component/path-to-regexp.git"
+    "url": "git+https://github.com/pillarjs/path-to-regexp.git"
   },
   "scripts": {
     "test": "istanbul cover _mocha -- -R spec"
   },
-  "version": "0.1.7"
+  "version": "0.1.12"
 }

+ 6 - 0
express-server/node_modules/qs/.editorconfig

@@ -38,3 +38,9 @@ indent_size = off
 indent_style = off
 indent = off
 max_line_length = off
+
+[.nycrc]
+indent_style = tab
+
+[tea.yaml]
+indent_size = 2

+ 5 - 5
express-server/node_modules/qs/.eslintrc

@@ -14,8 +14,8 @@
         "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
         "indent": [2, 4],
         "max-lines-per-function": [2, { "max": 150 }],
-        "max-params": [2, 15],
-        "max-statements": [2, 52],
+        "max-params": [2, 18],
+        "max-statements": [2, 100],
         "multiline-comment-style": 0,
         "no-continue": 1,
         "no-magic-numbers": 0,
@@ -32,7 +32,7 @@
                 "no-buffer-constructor": 0,
                 "no-extend-native": 0,
                 "no-throw-literal": 0,
-            }
-        }
-    ]
+            },
+        },
+    ],
 }

+ 213 - 1
express-server/node_modules/qs/CHANGELOG.md

@@ -1,3 +1,69 @@
+## **6.13.0**
+- [New] `parse`: add `strictDepth` option (#511)
+- [Tests] use `npm audit` instead of `aud`
+
+## **6.12.3**
+- [Fix] `parse`: properly account for `strictNullHandling` when `allowEmptyArrays`
+- [meta] fix changelog indentation
+
+## **6.12.2**
+- [Fix] `parse`: parse encoded square brackets (#506)
+- [readme] add CII best practices badge
+
+## **6.12.1**
+- [Fix] `parse`: Disable `decodeDotInKeys` by default to restore previous behavior (#501)
+- [Performance] `utils`: Optimize performance under large data volumes, reduce memory usage, and speed up processing (#502)
+- [Refactor] `utils`: use `+=`
+- [Tests] increase coverage
+
+## **6.12.0**
+
+- [New] `parse`/`stringify`: add `decodeDotInKeys`/`encodeDotKeys` options (#488)
+- [New] `parse`: add `duplicates` option
+- [New] `parse`/`stringify`: add `allowEmptyArrays` option to allow [] in object values (#487)
+- [Refactor] `parse`/`stringify`: move allowDots config logic to its own variable
+- [Refactor] `stringify`: move option-handling code into `normalizeStringifyOptions`
+- [readme] update readme, add logos (#484)
+- [readme] `stringify`: clarify default `arrayFormat` behavior
+- [readme] fix line wrapping
+- [readme] remove dead badges
+- [Deps] update `side-channel`
+- [meta] make the dist build 50% smaller
+- [meta] add `sideEffects` flag
+- [meta] run build in prepack, not prepublish
+- [Tests] `parse`: remove useless tests; add coverage
+- [Tests] `stringify`: increase coverage
+- [Tests] use `mock-property`
+- [Tests] `stringify`: improve coverage
+- [Dev Deps] update `@ljharb/eslint-config `, `aud`, `has-override-mistake`, `has-property-descriptors`, `mock-property`, `npmignore`, `object-inspect`, `tape`
+- [Dev Deps] pin `glob`, since v10.3.8+ requires a broken `jackspeak`
+- [Dev Deps] pin `jackspeak` since 2.1.2+ depends on npm aliases, which kill the install process in npm < 6
+
+## **6.11.2**
+- [Fix] `parse`: Fix parsing when the global Object prototype is frozen (#473)
+- [Tests] add passing test cases with empty keys (#473)
+
+## **6.11.1**
+- [Fix] `stringify`: encode comma values more consistently (#463)
+- [readme] add usage of `filter` option for injecting custom serialization, i.e. of custom types (#447)
+- [meta] remove extraneous code backticks (#457)
+- [meta] fix changelog markdown
+- [actions] update checkout action
+- [actions] restrict action permissions
+- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `object-inspect`, `tape`
+
+## **6.11.0**
+- [New] [Fix] `stringify`: revert 0e903c0; add `commaRoundTrip` option (#442)
+- [readme] fix version badge
+
+## **6.10.5**
+- [Fix] `stringify`: with `arrayFormat: comma`, properly include an explicit `[]` on a single-item array (#434)
+
+## **6.10.4**
+- [Fix] `stringify`: with `arrayFormat: comma`, include an explicit `[]` on a single-item array (#441)
+- [meta] use `npmignore` to autogenerate an npmignore file
+- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud`, `has-symbol`, `object-inspect`, `tape`
+
 ## **6.10.3**
 - [Fix] `parse`: ignore `__proto__` keys (#428)
 - [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
@@ -27,6 +93,18 @@
 - [Tests] use `ljharb/actions/node/install` instead of `ljharb/actions/node/run`
 - [Tests] Revert "[meta] ignore eclint transitive audit warning"
 
+## **6.9.7**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424)
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [readme] remove travis badge; add github actions/codecov badges; update URLs
+- [Docs] add note and links for coercing primitive values (#408)
+- [Tests] clean up stringify tests slightly
+- [meta] fix README.md (#399)
+- Revert "[meta] ignore eclint transitive audit warning"
+- [actions] backport actions from main
+- [Dev Deps] backport updates from main
+
 ## **6.9.6**
 - [Fix] restore `dist` dir; mistakenly removed in d4f6c32
 
@@ -75,6 +153,19 @@
 - [Tests] up to `node` `v12.10`, `v11.15`, `v10.16`, `v8.16`
 - [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray
 
+## **6.8.3**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424)
+- [readme] remove travis badge; add github actions/codecov badges; update URLs
+- [Tests] clean up stringify tests slightly
+- [Docs] add note and links for coercing primitive values (#408)
+- [meta] fix README.md (#399)
+- [actions] backport actions from main
+- [Dev Deps] backport updates from main
+- [Refactor] `stringify`: reduce branching
+- [meta] do not publish workflow files
+
 ## **6.8.2**
 - [Fix] proper comma parsing of URL-encoded commas (#361)
 - [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336)
@@ -106,6 +197,19 @@
 - [meta] add FUNDING.yml
 - [meta] Clean up license text so it’s properly detected as BSD-3-Clause
 
+## **6.7.3**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424)
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [readme] remove travis badge; add github actions/codecov badges; update URLs
+- [Docs] add note and links for coercing primitive values (#408)
+- [meta] fix README.md (#399)
+- [meta] do not publish workflow files
+- [actions] backport actions from main
+- [Dev Deps] backport updates from main
+- [Tests] use `nyc` for coverage
+- [Tests] clean up stringify tests slightly
+
 ## **6.7.2**
 - [Fix] proper comma parsing of URL-encoded commas (#361)
 - [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336)
@@ -144,6 +248,32 @@
 - [Tests] fix Buffer tests to work in node < 4.5 and node < 5.10
 - [Tests] temporarily allow coverage to fail
 
+## **6.6.1**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
+- [Fix] `utils.merge`: avoid a crash with a null target and an array source
+- [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
+- [Fix] correctly parse nested arrays
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [Robustness] `stringify`: cache `Object.prototype.hasOwnProperty`
+- [Refactor] `formats`: tiny bit of cleanup.
+- [Refactor] `utils`: `isBuffer`: small tweak; add tests
+- [Refactor]: `stringify`/`utils`: cache `Array.isArray`
+- [Refactor] `utils`: reduce observable [[Get]]s
+- [Refactor] use cached `Array.isArray`
+- [Refactor] `parse`/`stringify`: make a function to normalize the options
+- [readme] remove travis badge; add github actions/codecov badges; update URLs
+- [Docs] Clarify the need for "arrayLimit" option
+- [meta] fix README.md (#399)
+- [meta] do not publish workflow files
+- [meta] Clean up license text so it’s properly detected as BSD-3-Clause
+- [meta] add FUNDING.yml
+- [meta] Fixes typo in CHANGELOG.md
+- [actions] backport actions from main
+- [Tests] fix Buffer tests to work in node < 4.5 and node < 5.10
+- [Tests] always use `String(x)` over `x.toString()`
+- [Dev Deps] backport from main
+
 ## **6.6.0**
 - [New] Add support for iso-8859-1, utf8 "sentinel" and numeric entities (#268)
 - [New] move two-value combine to a `utils` function (#189)
@@ -160,6 +290,30 @@
 - [Dev Deps] update `browserify`, `eslint`, `@ljharb/eslint-config`, `iconv-lite`, `safe-publish-latest`, `tape`
 - [Tests] up to `node` `v10.10`, `v9.11`, `v8.12`, `v6.14`, `v4.9`; pin included builds to LTS
 
+## **6.5.3**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
+- [Fix] correctly parse nested arrays
+- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
+- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
+- [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
+- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
+- [Fix] `utils.merge`: avoid a crash with a null target and an array source
+- [Refactor] `utils`: reduce observable [[Get]]s
+- [Refactor] use cached `Array.isArray`
+- [Refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269)
+- [Refactor] `parse`: only need to reassign the var once
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [readme] remove travis badge; add github actions/codecov badges; update URLs
+- [Docs] Clean up license text so it’s properly detected as BSD-3-Clause
+- [Docs] Clarify the need for "arrayLimit" option
+- [meta] fix README.md (#399)
+- [meta] add FUNDING.yml
+- [actions] backport actions from main
+- [Tests] always use `String(x)` over `x.toString()`
+- [Tests] remove nonexistent tape option
+- [Dev Deps] backport from main
+
 ## **6.5.2**
 - [Fix] use `safer-buffer` instead of `Buffer` constructor
 - [Refactor] utils: `module.exports` one thing, instead of mutating `exports` (#230)
@@ -186,6 +340,27 @@
 - [Tests] up to `node` `v8.1`, `v7.10`, `v6.11`; npm v4.6 breaks on node < v1; npm v5+ breaks on node < v4
 - [Tests] add `editorconfig-tools`
 
+## **6.4.1**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
+- [Fix] use `safer-buffer` instead of `Buffer` constructor
+- [Fix] `utils.merge`: avoid a crash with a null target and an array source
+- [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
+- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
+- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
+- [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [Refactor] use cached `Array.isArray`
+- [Refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269)
+- [readme] remove travis badge; add github actions/codecov badges; update URLs
+- [Docs] Clarify the need for "arrayLimit" option
+- [meta] fix README.md (#399)
+- [meta] Clean up license text so it’s properly detected as BSD-3-Clause
+- [meta] add FUNDING.yml
+- [actions] backport actions from main
+- [Tests] remove nonexistent tape option
+- [Dev Deps] backport from main
+
 ## **6.4.0**
 - [New] `qs.stringify`: add `encodeValuesOnly` option
 - [Fix] follow `allowPrototypes` option during merge (#201, #201)
@@ -195,6 +370,26 @@
 - [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
 - [eslint] reduce warnings
 
+## **6.3.3**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
+- [Fix] `utils.merge`: avoid a crash with a null target and an array source
+- [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
+- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
+- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
+- [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [Refactor] use cached `Array.isArray`
+- [Refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269)
+- [Docs] Clarify the need for "arrayLimit" option
+- [meta] fix README.md (#399)
+- [meta] Clean up license text so it’s properly detected as BSD-3-Clause
+- [meta] add FUNDING.yml
+- [actions] backport actions from main
+- [Tests] use `safer-buffer` instead of `Buffer` constructor
+- [Tests] remove nonexistent tape option
+- [Dev Deps] backport from main
+
 ## **6.3.2**
 - [Fix] follow `allowPrototypes` option during merge (#201, #200)
 - [Dev Deps] update `eslint`
@@ -228,6 +423,23 @@
 - [Tests] skip Object.create tests when null objects are not available
 - [Tests] Turn on eslint for test files (#175)
 
+## **6.2.4**
+- [Fix] `parse`: ignore `__proto__` keys (#428)
+- [Fix] `utils.merge`: avoid a crash with a null target and an array source
+- [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
+- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
+- [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
+- [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
+- [Refactor] use cached `Array.isArray`
+- [Docs] Clarify the need for "arrayLimit" option
+- [meta] fix README.md (#399)
+- [meta] Clean up license text so it’s properly detected as BSD-3-Clause
+- [meta] add FUNDING.yml
+- [actions] backport actions from main
+- [Tests] use `safer-buffer` instead of `Buffer` constructor
+- [Tests] remove nonexistent tape option
+- [Dev Deps] backport from main
+
 ## **6.2.3**
 - [Fix] follow `allowPrototypes` option during merge (#201, #200)
 - [Fix] chmod a-x
@@ -249,7 +461,7 @@
 - [New] add "encoder" and "decoder" options, for custom param encoding/decoding (#160)
 - [Fix] fix compacting of nested sparse arrays (#150)
 
-## **6.1.2
+## **6.1.2**
 - [Fix] follow `allowPrototypes` option during merge (#201, #200)
 - [Fix] chmod a-x
 - [Fix] support keys starting with brackets (#202, #200)

+ 136 - 50
express-server/node_modules/qs/README.md

@@ -1,11 +1,14 @@
-# qs <sup>[![Version Badge][2]][1]</sup>
+<p align="center">
+    <img alt="qs" src="./logos/banner_default.png" width="800" />
+</p>
+
+# qs <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
 
 [![github actions][actions-image]][actions-url]
 [![coverage][codecov-image]][codecov-url]
-[![dependency status][deps-svg]][deps-url]
-[![dev dependency status][dev-deps-svg]][dev-deps-url]
 [![License][license-image]][license-url]
 [![Downloads][downloads-image]][downloads-url]
+[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/9058/badge)](https://bestpractices.coreinfrastructure.org/projects/9058)
 
 [![npm badge][npm-badge-png]][package-url]
 
@@ -53,7 +56,9 @@ var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
 assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
 ```
 
-By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.
+By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties.
+*WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten.
+Always be careful with this option.
 
 ```javascript
 var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
@@ -80,8 +85,8 @@ assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
 });
 ```
 
-By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like
-`'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
+By default, when nesting objects **qs** will only parse up to 5 children deep.
+This means if you attempt to parse a string like `'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
 
 ```javascript
 var expected = {
@@ -110,7 +115,18 @@ var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
 assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
 ```
 
-The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number.
+You can configure **qs** to throw an error when parsing nested input beyond this depth using the `strictDepth` option (defaulted to false):
+
+```javascript
+try {
+    qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1, strictDepth: true });
+} catch (err) {
+    assert(err instanceof RangeError);
+    assert.strictEqual(err.message, 'Input depth exceeded depth option of 1 and strictDepth is true');
+}
+```
+
+The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number. The strictDepth option adds a layer of protection by throwing an error when the limit is exceeded, allowing you to catch and handle such cases.
 
 For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
 
@@ -147,32 +163,44 @@ var withDots = qs.parse('a.b=c', { allowDots: true });
 assert.deepEqual(withDots, { a: { b: 'c' } });
 ```
 
-If you have to deal with legacy browsers or services, there's
-also support for decoding percent-encoded octets as iso-8859-1:
+Option `decodeDotInKeys` can be used to decode dots in keys
+Note: it implies `allowDots`, so `parse` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.
+
+```javascript
+var withDots = qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { decodeDotInKeys: true });
+assert.deepEqual(withDots, { 'name.obj': { first: 'John', last: 'Doe' }});
+```
+
+Option `allowEmptyArrays` can be used to allowing empty array values in object
+```javascript
+var withEmptyArrays = qs.parse('foo[]&bar=baz', { allowEmptyArrays: true });
+assert.deepEqual(withEmptyArrays, { foo: [], bar: 'baz' });
+```
+
+Option `duplicates` can be used to change the behavior when duplicate keys are encountered
+```javascript
+assert.deepEqual(qs.parse('foo=bar&foo=baz'), { foo: ['bar', 'baz'] });
+assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }), { foo: ['bar', 'baz'] });
+assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'first' }), { foo: 'bar' });
+assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'last' }), { foo: 'baz' });
+```
+
+If you have to deal with legacy browsers or services, there's also support for decoding percent-encoded octets as iso-8859-1:
 
 ```javascript
 var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });
 assert.deepEqual(oldCharset, { a: '§' });
 ```
 
-Some services add an initial `utf8=✓` value to forms so that old
-Internet Explorer versions are more likely to submit the form as
-utf-8. Additionally, the server can check the value against wrong
-encodings of the checkmark character and detect that a query string
-or `application/x-www-form-urlencoded` body was *not* sent as
-utf-8, eg. if the form had an `accept-charset` parameter or the
-containing page had a different character set.
+Some services add an initial `utf8=✓` value to forms so that old Internet Explorer versions are more likely to submit the form as utf-8.
+Additionally, the server can check the value against wrong encodings of the checkmark character and detect that a query string or `application/x-www-form-urlencoded` body was *not* sent as utf-8, eg. if the form had an `accept-charset` parameter or the containing page had a different character set.
 
 **qs** supports this mechanism via the `charsetSentinel` option.
-If specified, the `utf8` parameter will be omitted from the
-returned object. It will be used to switch to `iso-8859-1`/`utf-8`
-mode depending on how the checkmark is encoded.
+If specified, the `utf8` parameter will be omitted from the returned object.
+It will be used to switch to `iso-8859-1`/`utf-8` mode depending on how the checkmark is encoded.
 
-**Important**: When you specify both the `charset` option and the
-`charsetSentinel` option, the `charset` will be overridden when
-the request contains a `utf8` parameter from which the actual
-charset can be deduced. In that sense the `charset` will behave
-as the default charset rather than the authoritative charset.
+**Important**: When you specify both the `charset` option and the `charsetSentinel` option, the `charset` will be overridden when the request contains a `utf8` parameter from which the actual charset can be deduced.
+In that sense the `charset` will behave as the default charset rather than the authoritative charset.
 
 ```javascript
 var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', {
@@ -189,8 +217,7 @@ var detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', {
 assert.deepEqual(detectedAsIso8859_1, { a: 'ø' });
 ```
 
-If you want to decode the `&#...;` syntax to the actual character,
-you can specify the `interpretNumericEntities` option as well:
+If you want to decode the `&#...;` syntax to the actual character, you can specify the `interpretNumericEntities` option as well:
 
 ```javascript
 var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
@@ -200,8 +227,7 @@ var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
 assert.deepEqual(detectedAsIso8859_1, { a: '☺' });
 ```
 
-It also works when the charset has been detected in `charsetSentinel`
-mode.
+It also works when the charset has been detected in `charsetSentinel` mode.
 
 ### Parsing Arrays
 
@@ -219,9 +245,8 @@ var withIndexes = qs.parse('a[1]=c&a[0]=b');
 assert.deepEqual(withIndexes, { a: ['b', 'c'] });
 ```
 
-Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number
-to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving
-their order:
+Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number to create an array.
+When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving their order:
 
 ```javascript
 var noSparse = qs.parse('a[1]=b&a[15]=c');
@@ -245,8 +270,9 @@ var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
 assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
 ```
 
-**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
-instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
+**qs** will also limit specifying indices in an array to a maximum index of `20`.
+Any array members with an index of greater than `20` will instead be converted to an object with the index as the key.
+This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
 
 ```javascript
 var withMaxIndex = qs.parse('a[100]=b');
@@ -290,7 +316,8 @@ assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
 
 ### Parsing primitive/scalar values (numbers, booleans, null, etc)
 
-By default, all values are parsed as strings. This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91).
+By default, all values are parsed as strings.
+This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91).
 
 ```javascript
 var primitiveValues = qs.parse('a=15&b=true&c=null');
@@ -373,16 +400,17 @@ var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset,
 }})
 ```
 
-Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
+Examples beyond this point will be shown as though the output is not URI encoded for clarity.
+Please note that the return values in these cases *will* be URI encoded during real usage.
 
-When arrays are stringified, by default they are given explicit indices:
+When arrays are stringified, they follow the `arrayFormat` option, which defaults to `indices`:
 
 ```javascript
 qs.stringify({ a: ['b', 'c', 'd'] });
 // 'a[0]=b&a[1]=c&a[2]=d'
 ```
 
-You may override this by setting the `indices` option to `false`:
+You may override this by setting the `indices` option to `false`, or to be more explicit, the `arrayFormat` option to `repeat`:
 
 ```javascript
 qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
@@ -402,6 +430,8 @@ qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
 // 'a=b,c'
 ```
 
+Note: when using `arrayFormat` set to `'comma'`, you can also pass the `commaRoundTrip` option set to `true` or `false`, to append `[]` on single-item arrays, so that they can round trip through a parse.
+
 When objects are stringified, by default they use bracket notation:
 
 ```javascript
@@ -416,6 +446,20 @@ qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
 // 'a.b.c=d&a.b.e=f'
 ```
 
+You may encode the dot notation in the keys of object with option `encodeDotInKeys` by setting it to `true`:
+Note: it implies `allowDots`, so `stringify` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.
+Caveat: when `encodeValuesOnly` is `true` as well as `encodeDotInKeys`, only dots in keys and nothing else will be encoded.
+```javascript
+qs.stringify({ "name.obj": { "first": "John", "last": "Doe" } }, { allowDots: true, encodeDotInKeys: true })
+// 'name%252Eobj.first=John&name%252Eobj.last=Doe'
+```
+
+You may allow empty array values by setting the `allowEmptyArrays` option to `true`:
+```javascript
+qs.stringify({ foo: [], bar: 'baz' }, { allowEmptyArrays: true });
+// 'foo[]&bar=baz'
+```
+
 Empty strings and null values will omit the value, but the equals sign (=) remains in place:
 
 ```javascript
@@ -471,8 +515,8 @@ assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort
 ```
 
 Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
-If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
-pass an array, it will be used to select properties and array indices for stringification:
+If you pass a function, it will be called for each key to obtain the replacement value.
+Otherwise, if you pass an array, it will be used to select properties and array indices for stringification:
 
 ```javascript
 function filterFunc(prefix, value) {
@@ -496,6 +540,44 @@ qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
 // 'a[0]=b&a[2]=d'
 ```
 
+You could also use `filter` to inject custom serialization for user defined types.
+Consider you're working with some api that expects query strings of the format for ranges:
+
+```
+https://domain.com/endpoint?range=30...70
+```
+
+For which you model as:
+
+```javascript
+class Range {
+    constructor(from, to) {
+        this.from = from;
+        this.to = to;
+    }
+}
+```
+
+You could _inject_ a custom serializer to handle values of this type:
+
+```javascript
+qs.stringify(
+    {
+        range: new Range(30, 70),
+    },
+    {
+        filter: (prefix, value) => {
+            if (value instanceof Range) {
+                return `${value.from}...${value.to}`;
+            }
+            // serialize the usual way
+            return value;
+        },
+    }
+);
+// range=30...70
+```
+
 ### Handling of `null` values
 
 By default, `null` values are treated like empty strings:
@@ -505,7 +587,8 @@ var withNull = qs.stringify({ a: null, b: '' });
 assert.equal(withNull, 'a=&b=');
 ```
 
-Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
+Parsing does not distinguish between parameters with and without equal signs.
+Both are converted to empty strings.
 
 ```javascript
 var equalsInsensitive = qs.parse('a&b=');
@@ -534,25 +617,21 @@ var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
 assert.equal(nullsSkipped, 'a=b');
 ```
 
-If you're communicating with legacy systems, you can switch to `iso-8859-1`
-using the `charset` option:
+If you're communicating with legacy systems, you can switch to `iso-8859-1` using the `charset` option:
 
 ```javascript
 var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
 assert.equal(iso, '%E6=%E6');
 ```
 
-Characters that don't exist in `iso-8859-1` will be converted to numeric
-entities, similar to what browsers do:
+Characters that don't exist in `iso-8859-1` will be converted to numeric entities, similar to what browsers do:
 
 ```javascript
 var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
 assert.equal(numeric, 'a=%26%239786%3B');
 ```
 
-You can use the `charsetSentinel` option to announce the character by
-including an `utf8=✓` parameter with the proper encoding if the checkmark,
-similar to what Ruby on Rails and others do when submitting forms.
+You can use the `charsetSentinel` option to announce the character by including an `utf8=✓` parameter with the proper encoding if the checkmark, similar to what Ruby on Rails and others do when submitting forms.
 
 ```javascript
 var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
@@ -564,8 +643,7 @@ assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');
 
 ### Dealing with special character sets
 
-By default the encoding and decoding of characters is done in `utf-8`,
-and `iso-8859-1` support is also built in via the `charset` parameter.
+By default the encoding and decoding of characters is done in `utf-8`, and `iso-8859-1` support is also built in via the `charset` parameter.
 
 If you wish to encode querystrings to a different character set (i.e.
 [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
@@ -604,7 +682,9 @@ Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/se
 
 Available as part of the Tidelift Subscription
 
-The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
+The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications.
+Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
+[Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
 
 [package-url]: https://npmjs.org/package/qs
 [npm-version-svg]: https://versionbadg.es/ljharb/qs.svg
@@ -621,3 +701,9 @@ The maintainers of qs and thousands of other packages are working with Tidelift
 [codecov-url]: https://app.codecov.io/gh/ljharb/qs/
 [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs
 [actions-url]: https://github.com/ljharb/qs/actions
+
+## Acknowledgements
+
+qs logo by [NUMI](https://github.com/numi-hq/open-design):
+
+[<img src="https://raw.githubusercontent.com/numi-hq/open-design/main/assets/numi-lockup.png" alt="NUMI Logo" style="width: 200px;"/>](https://numi.tech/?ref=qs)

File diff suppressed because it is too large
+ 56 - 2010
express-server/node_modules/qs/dist/qs.js


+ 46 - 13
express-server/node_modules/qs/lib/parse.js

@@ -7,20 +7,24 @@ var isArray = Array.isArray;
 
 var defaults = {
     allowDots: false,
+    allowEmptyArrays: false,
     allowPrototypes: false,
     allowSparse: false,
     arrayLimit: 20,
     charset: 'utf-8',
     charsetSentinel: false,
     comma: false,
+    decodeDotInKeys: false,
     decoder: utils.decode,
     delimiter: '&',
     depth: 5,
+    duplicates: 'combine',
     ignoreQueryPrefix: false,
     interpretNumericEntities: false,
     parameterLimit: 1000,
     parseArrays: true,
     plainObjects: false,
+    strictDepth: false,
     strictNullHandling: false
 };
 
@@ -49,8 +53,10 @@ var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('&#10003;')
 var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
 
 var parseValues = function parseQueryStringValues(str, options) {
-    var obj = {};
+    var obj = { __proto__: null };
+
     var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
+    cleanStr = cleanStr.replace(/%5B/gi, '[').replace(/%5D/gi, ']');
     var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
     var parts = cleanStr.split(options.delimiter, limit);
     var skipIndex = -1; // Keep track of where the utf8 sentinel was found
@@ -102,9 +108,10 @@ var parseValues = function parseQueryStringValues(str, options) {
             val = isArray(val) ? [val] : val;
         }
 
-        if (has.call(obj, key)) {
+        var existing = has.call(obj, key);
+        if (existing && options.duplicates === 'combine') {
             obj[key] = utils.combine(obj[key], val);
-        } else {
+        } else if (!existing || options.duplicates === 'last') {
             obj[key] = val;
         }
     }
@@ -120,24 +127,27 @@ var parseObject = function (chain, val, options, valuesParsed) {
         var root = chain[i];
 
         if (root === '[]' && options.parseArrays) {
-            obj = [].concat(leaf);
+            obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
+                ? []
+                : [].concat(leaf);
         } else {
             obj = options.plainObjects ? Object.create(null) : {};
             var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
-            var index = parseInt(cleanRoot, 10);
-            if (!options.parseArrays && cleanRoot === '') {
+            var decodedRoot = options.decodeDotInKeys ? cleanRoot.replace(/%2E/g, '.') : cleanRoot;
+            var index = parseInt(decodedRoot, 10);
+            if (!options.parseArrays && decodedRoot === '') {
                 obj = { 0: leaf };
             } else if (
                 !isNaN(index)
-                && root !== cleanRoot
-                && String(index) === cleanRoot
+                && root !== decodedRoot
+                && String(index) === decodedRoot
                 && index >= 0
                 && (options.parseArrays && index <= options.arrayLimit)
             ) {
                 obj = [];
                 obj[index] = leaf;
-            } else if (cleanRoot !== '__proto__') {
-                obj[cleanRoot] = leaf;
+            } else if (decodedRoot !== '__proto__') {
+                obj[decodedRoot] = leaf;
             }
         }
 
@@ -192,9 +202,12 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
         keys.push(segment[1]);
     }
 
-    // If there's a remainder, just add whatever is left
+    // If there's a remainder, check strictDepth option for throw, else just add whatever is left
 
     if (segment) {
+        if (options.strictDepth === true) {
+            throw new RangeError('Input depth exceeded depth option of ' + options.depth + ' and strictDepth is true');
+        }
         keys.push('[' + key.slice(segment.index) + ']');
     }
 
@@ -206,7 +219,15 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
         return defaults;
     }
 
-    if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') {
+    if (typeof opts.allowEmptyArrays !== 'undefined' && typeof opts.allowEmptyArrays !== 'boolean') {
+        throw new TypeError('`allowEmptyArrays` option can only be `true` or `false`, when provided');
+    }
+
+    if (typeof opts.decodeDotInKeys !== 'undefined' && typeof opts.decodeDotInKeys !== 'boolean') {
+        throw new TypeError('`decodeDotInKeys` option can only be `true` or `false`, when provided');
+    }
+
+    if (opts.decoder !== null && typeof opts.decoder !== 'undefined' && typeof opts.decoder !== 'function') {
         throw new TypeError('Decoder has to be a function.');
     }
 
@@ -215,23 +236,35 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
     }
     var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
 
+    var duplicates = typeof opts.duplicates === 'undefined' ? defaults.duplicates : opts.duplicates;
+
+    if (duplicates !== 'combine' && duplicates !== 'first' && duplicates !== 'last') {
+        throw new TypeError('The duplicates option must be either combine, first, or last');
+    }
+
+    var allowDots = typeof opts.allowDots === 'undefined' ? opts.decodeDotInKeys === true ? true : defaults.allowDots : !!opts.allowDots;
+
     return {
-        allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
+        allowDots: allowDots,
+        allowEmptyArrays: typeof opts.allowEmptyArrays === 'boolean' ? !!opts.allowEmptyArrays : defaults.allowEmptyArrays,
         allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes,
         allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse,
         arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit,
         charset: charset,
         charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
         comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
+        decodeDotInKeys: typeof opts.decodeDotInKeys === 'boolean' ? opts.decodeDotInKeys : defaults.decodeDotInKeys,
         decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
         delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
         // eslint-disable-next-line no-implicit-coercion, no-extra-parens
         depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
+        duplicates: duplicates,
         ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
         interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
         parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
         parseArrays: opts.parseArrays !== false,
         plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects,
+        strictDepth: typeof opts.strictDepth === 'boolean' ? !!opts.strictDepth : defaults.strictDepth,
         strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
     };
 };

+ 57 - 23
express-server/node_modules/qs/lib/stringify.js

@@ -19,7 +19,6 @@ var arrayPrefixGenerators = {
 };
 
 var isArray = Array.isArray;
-var split = String.prototype.split;
 var push = Array.prototype.push;
 var pushToArray = function (arr, valueOrArray) {
     push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
@@ -31,10 +30,13 @@ var defaultFormat = formats['default'];
 var defaults = {
     addQueryPrefix: false,
     allowDots: false,
+    allowEmptyArrays: false,
+    arrayFormat: 'indices',
     charset: 'utf-8',
     charsetSentinel: false,
     delimiter: '&',
     encode: true,
+    encodeDotInKeys: false,
     encoder: utils.encode,
     encodeValuesOnly: false,
     format: defaultFormat,
@@ -62,8 +64,11 @@ var stringify = function stringify(
     object,
     prefix,
     generateArrayPrefix,
+    commaRoundTrip,
+    allowEmptyArrays,
     strictNullHandling,
     skipNulls,
+    encodeDotInKeys,
     encoder,
     filter,
     sort,
@@ -120,14 +125,6 @@ var stringify = function stringify(
     if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
         if (encoder) {
             var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);
-            if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
-                var valuesArray = split.call(String(obj), ',');
-                var valuesJoined = '';
-                for (var i = 0; i < valuesArray.length; ++i) {
-                    valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));
-                }
-                return [formatter(keyValue) + '=' + valuesJoined];
-            }
             return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
         }
         return [formatter(prefix) + '=' + formatter(String(obj))];
@@ -142,6 +139,9 @@ var stringify = function stringify(
     var objKeys;
     if (generateArrayPrefix === 'comma' && isArray(obj)) {
         // we need to join elements in
+        if (encodeValuesOnly && encoder) {
+            obj = utils.maybeMap(obj, encoder);
+        }
         objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
     } else if (isArray(filter)) {
         objKeys = filter;
@@ -150,6 +150,14 @@ var stringify = function stringify(
         objKeys = sort ? keys.sort(sort) : keys;
     }
 
+    var encodedPrefix = encodeDotInKeys ? prefix.replace(/\./g, '%2E') : prefix;
+
+    var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? encodedPrefix + '[]' : encodedPrefix;
+
+    if (allowEmptyArrays && isArray(obj) && obj.length === 0) {
+        return adjustedPrefix + '[]';
+    }
+
     for (var j = 0; j < objKeys.length; ++j) {
         var key = objKeys[j];
         var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];
@@ -158,9 +166,10 @@ var stringify = function stringify(
             continue;
         }
 
+        var encodedKey = allowDots && encodeDotInKeys ? key.replace(/\./g, '%2E') : key;
         var keyPrefix = isArray(obj)
-            ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix
-            : prefix + (allowDots ? '.' + key : '[' + key + ']');
+            ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, encodedKey) : adjustedPrefix
+            : adjustedPrefix + (allowDots ? '.' + encodedKey : '[' + encodedKey + ']');
 
         sideChannel.set(object, step);
         var valueSideChannel = getSideChannel();
@@ -169,9 +178,12 @@ var stringify = function stringify(
             value,
             keyPrefix,
             generateArrayPrefix,
+            commaRoundTrip,
+            allowEmptyArrays,
             strictNullHandling,
             skipNulls,
-            encoder,
+            encodeDotInKeys,
+            generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder,
             filter,
             sort,
             allowDots,
@@ -192,6 +204,14 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
         return defaults;
     }
 
+    if (typeof opts.allowEmptyArrays !== 'undefined' && typeof opts.allowEmptyArrays !== 'boolean') {
+        throw new TypeError('`allowEmptyArrays` option can only be `true` or `false`, when provided');
+    }
+
+    if (typeof opts.encodeDotInKeys !== 'undefined' && typeof opts.encodeDotInKeys !== 'boolean') {
+        throw new TypeError('`encodeDotInKeys` option can only be `true` or `false`, when provided');
+    }
+
     if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
         throw new TypeError('Encoder has to be a function.');
     }
@@ -215,13 +235,32 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
         filter = opts.filter;
     }
 
+    var arrayFormat;
+    if (opts.arrayFormat in arrayPrefixGenerators) {
+        arrayFormat = opts.arrayFormat;
+    } else if ('indices' in opts) {
+        arrayFormat = opts.indices ? 'indices' : 'repeat';
+    } else {
+        arrayFormat = defaults.arrayFormat;
+    }
+
+    if ('commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') {
+        throw new TypeError('`commaRoundTrip` must be a boolean, or absent');
+    }
+
+    var allowDots = typeof opts.allowDots === 'undefined' ? opts.encodeDotInKeys === true ? true : defaults.allowDots : !!opts.allowDots;
+
     return {
         addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,
-        allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
+        allowDots: allowDots,
+        allowEmptyArrays: typeof opts.allowEmptyArrays === 'boolean' ? !!opts.allowEmptyArrays : defaults.allowEmptyArrays,
+        arrayFormat: arrayFormat,
         charset: charset,
         charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
+        commaRoundTrip: opts.commaRoundTrip,
         delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,
         encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,
+        encodeDotInKeys: typeof opts.encodeDotInKeys === 'boolean' ? opts.encodeDotInKeys : defaults.encodeDotInKeys,
         encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,
         encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,
         filter: filter,
@@ -255,16 +294,8 @@ module.exports = function (object, opts) {
         return '';
     }
 
-    var arrayFormat;
-    if (opts && opts.arrayFormat in arrayPrefixGenerators) {
-        arrayFormat = opts.arrayFormat;
-    } else if (opts && 'indices' in opts) {
-        arrayFormat = opts.indices ? 'indices' : 'repeat';
-    } else {
-        arrayFormat = 'indices';
-    }
-
-    var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
+    var generateArrayPrefix = arrayPrefixGenerators[options.arrayFormat];
+    var commaRoundTrip = generateArrayPrefix === 'comma' && options.commaRoundTrip;
 
     if (!objKeys) {
         objKeys = Object.keys(obj);
@@ -285,8 +316,11 @@ module.exports = function (object, opts) {
             obj[key],
             key,
             generateArrayPrefix,
+            commaRoundTrip,
+            options.allowEmptyArrays,
             options.strictNullHandling,
             options.skipNulls,
+            options.encodeDotInKeys,
             options.encode ? options.encoder : null,
             options.filter,
             options.sort,

+ 47 - 34
express-server/node_modules/qs/lib/utils.js

@@ -122,6 +122,10 @@ var decode = function (str, decoder, charset) {
     }
 };
 
+var limit = 1024;
+
+/* eslint operator-linebreak: [2, "before"] */
+
 var encode = function encode(str, defaultEncoder, charset, kind, format) {
     // This code was originally written by Brian White (mscdex) for the io.js core querystring library.
     // It has been adapted here for stricter adherence to RFC 3986
@@ -143,45 +147,54 @@ var encode = function encode(str, defaultEncoder, charset, kind, format) {
     }
 
     var out = '';
-    for (var i = 0; i < string.length; ++i) {
-        var c = string.charCodeAt(i);
-
-        if (
-            c === 0x2D // -
-            || c === 0x2E // .
-            || c === 0x5F // _
-            || c === 0x7E // ~
-            || (c >= 0x30 && c <= 0x39) // 0-9
-            || (c >= 0x41 && c <= 0x5A) // a-z
-            || (c >= 0x61 && c <= 0x7A) // A-Z
-            || (format === formats.RFC1738 && (c === 0x28 || c === 0x29)) // ( )
-        ) {
-            out += string.charAt(i);
-            continue;
-        }
+    for (var j = 0; j < string.length; j += limit) {
+        var segment = string.length >= limit ? string.slice(j, j + limit) : string;
+        var arr = [];
+
+        for (var i = 0; i < segment.length; ++i) {
+            var c = segment.charCodeAt(i);
+            if (
+                c === 0x2D // -
+                || c === 0x2E // .
+                || c === 0x5F // _
+                || c === 0x7E // ~
+                || (c >= 0x30 && c <= 0x39) // 0-9
+                || (c >= 0x41 && c <= 0x5A) // a-z
+                || (c >= 0x61 && c <= 0x7A) // A-Z
+                || (format === formats.RFC1738 && (c === 0x28 || c === 0x29)) // ( )
+            ) {
+                arr[arr.length] = segment.charAt(i);
+                continue;
+            }
 
-        if (c < 0x80) {
-            out = out + hexTable[c];
-            continue;
-        }
+            if (c < 0x80) {
+                arr[arr.length] = hexTable[c];
+                continue;
+            }
 
-        if (c < 0x800) {
-            out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]);
-            continue;
-        }
+            if (c < 0x800) {
+                arr[arr.length] = hexTable[0xC0 | (c >> 6)]
+                    + hexTable[0x80 | (c & 0x3F)];
+                continue;
+            }
+
+            if (c < 0xD800 || c >= 0xE000) {
+                arr[arr.length] = hexTable[0xE0 | (c >> 12)]
+                    + hexTable[0x80 | ((c >> 6) & 0x3F)]
+                    + hexTable[0x80 | (c & 0x3F)];
+                continue;
+            }
+
+            i += 1;
+            c = 0x10000 + (((c & 0x3FF) << 10) | (segment.charCodeAt(i) & 0x3FF));
 
-        if (c < 0xD800 || c >= 0xE000) {
-            out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]);
-            continue;
+            arr[arr.length] = hexTable[0xF0 | (c >> 18)]
+                + hexTable[0x80 | ((c >> 12) & 0x3F)]
+                + hexTable[0x80 | ((c >> 6) & 0x3F)]
+                + hexTable[0x80 | (c & 0x3F)];
         }
 
-        i += 1;
-        c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
-        /* eslint operator-linebreak: [2, "before"] */
-        out += hexTable[0xF0 | (c >> 18)]
-            + hexTable[0x80 | ((c >> 12) & 0x3F)]
-            + hexTable[0x80 | ((c >> 6) & 0x3F)]
-            + hexTable[0x80 | (c & 0x3F)];
+        out += arr.join('');
     }
 
     return out;

+ 46 - 28
express-server/node_modules/qs/package.json

@@ -1,27 +1,27 @@
 {
-  "_from": "qs@6.10.3",
-  "_id": "qs@6.10.3",
+  "_from": "qs@6.13.0",
+  "_id": "qs@6.13.0",
   "_inBundle": false,
-  "_integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+  "_integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
   "_location": "/qs",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "qs@6.10.3",
+    "raw": "qs@6.13.0",
     "name": "qs",
     "escapedName": "qs",
-    "rawSpec": "6.10.3",
+    "rawSpec": "6.13.0",
     "saveSpec": null,
-    "fetchSpec": "6.10.3"
+    "fetchSpec": "6.13.0"
   },
   "_requiredBy": [
     "/body-parser",
     "/express"
   ],
-  "_resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
-  "_shasum": "d6cde1b2ffca87b5aa57889816c5f81535e22e8e",
-  "_spec": "qs@6.10.3",
+  "_resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+  "_shasum": "6ca3bd58439f7e245655798997787b0d88a51906",
+  "_spec": "qs@6.13.0",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "bugs": {
     "url": "https://github.com/ljharb/qs/issues"
@@ -35,28 +35,40 @@
     }
   ],
   "dependencies": {
-    "side-channel": "^1.0.4"
+    "side-channel": "^1.0.6"
   },
   "deprecated": false,
   "description": "A querystring parser that supports nesting and arrays, with a depth limit",
   "devDependencies": {
-    "@ljharb/eslint-config": "^20.1.0",
-    "aud": "^1.1.5",
+    "@browserify/envify": "^6.0.0",
+    "@browserify/uglifyify": "^6.0.0",
+    "@ljharb/eslint-config": "^21.1.1",
     "browserify": "^16.5.2",
+    "bundle-collapser": "^1.4.0",
+    "common-shakeify": "~1.0.0",
     "eclint": "^2.8.1",
-    "eslint": "^8.6.0",
+    "es-value-fixtures": "^1.4.2",
+    "eslint": "=8.8.0",
     "evalmd": "^0.0.19",
     "for-each": "^0.3.3",
-    "has-symbols": "^1.0.2",
+    "glob": "=10.3.7",
+    "has-override-mistake": "^1.0.1",
+    "has-property-descriptors": "^1.0.2",
+    "has-symbols": "^1.0.3",
     "iconv-lite": "^0.5.1",
     "in-publish": "^2.0.1",
+    "jackspeak": "=2.1.1",
     "mkdirp": "^0.5.5",
+    "mock-property": "^1.0.3",
+    "module-deps": "^6.2.3",
+    "npmignore": "^0.3.1",
     "nyc": "^10.3.2",
-    "object-inspect": "^1.12.0",
+    "object-inspect": "^1.13.2",
     "qs-iconv": "^1.0.4",
     "safe-publish-latest": "^2.0.0",
     "safer-buffer": "^2.1.2",
-    "tape": "^5.4.0"
+    "tape": "^5.8.1",
+    "unassertify": "^3.0.1"
   },
   "engines": {
     "node": ">=0.6"
@@ -64,12 +76,6 @@
   "funding": {
     "url": "https://github.com/sponsors/ljharb"
   },
-  "greenkeeper": {
-    "ignore": [
-      "iconv-lite",
-      "mkdirp"
-    ]
-  },
   "homepage": "https://github.com/ljharb/qs",
   "keywords": [
     "querystring",
@@ -82,21 +88,33 @@
   "license": "BSD-3-Clause",
   "main": "lib/index.js",
   "name": "qs",
+  "publishConfig": {
+    "ignore": [
+      "!dist/*",
+      "bower.json",
+      "component.json",
+      ".github/workflows",
+      "logos",
+      "tea.yaml"
+    ]
+  },
   "repository": {
     "type": "git",
     "url": "git+https://github.com/ljharb/qs.git"
   },
   "scripts": {
-    "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js",
-    "lint": "eslint .",
-    "postlint": "eclint check * lib/* test/* !dist/*",
-    "posttest": "aud --production",
+    "dist": "mkdirp dist && browserify --standalone Qs -g unassertify -g @browserify/envify -g [@browserify/uglifyify --mangle.keep_fnames --compress.keep_fnames --format.indent_level=1 --compress.arrows=false --compress.passes=4 --compress.typeofs=false] -p common-shakeify -p bundle-collapser/plugin lib/index.js > dist/qs.js",
+    "lint": "eslint --ext=js,mjs .",
+    "postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git' | grep -v dist/)",
+    "posttest": "npx npm@'>=10.2' audit --production",
+    "prepack": "npmignore --auto --commentLines=autogenerated && npm run dist",
     "prepublish": "not-in-publish || npm run prepublishOnly",
-    "prepublishOnly": "safe-publish-latest && npm run dist",
+    "prepublishOnly": "safe-publish-latest",
     "pretest": "npm run --silent readme && npm run --silent lint",
     "readme": "evalmd README.md",
     "test": "npm run tests-only",
     "tests-only": "nyc tape 'test/**/*.js'"
   },
-  "version": "6.10.3"
+  "sideEffects": false,
+  "version": "6.13.0"
 }

+ 361 - 32
express-server/node_modules/qs/test/parse.js

@@ -1,10 +1,17 @@
 'use strict';
 
 var test = require('tape');
-var qs = require('../');
-var utils = require('../lib/utils');
+var hasPropertyDescriptors = require('has-property-descriptors')();
 var iconv = require('iconv-lite');
+var mockProperty = require('mock-property');
+var hasOverrideMistake = require('has-override-mistake')();
 var SaferBuffer = require('safer-buffer').Buffer;
+var v = require('es-value-fixtures');
+var inspect = require('object-inspect');
+var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
+
+var qs = require('../');
+var utils = require('../lib/utils');
 
 test('parse()', function (t) {
     t.test('parses a simple string', function (st) {
@@ -32,41 +39,156 @@ test('parse()', function (t) {
         st.end();
     });
 
-    t.test('arrayFormat: brackets allows only explicit arrays', function (st) {
-        st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'brackets' }), { a: 'b,c' });
-        st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
+    t.test('comma: false', function (st) {
+        st.deepEqual(qs.parse('a[]=b&a[]=c'), { a: ['b', 'c'] });
+        st.deepEqual(qs.parse('a[0]=b&a[1]=c'), { a: ['b', 'c'] });
+        st.deepEqual(qs.parse('a=b,c'), { a: 'b,c' });
+        st.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] });
         st.end();
     });
 
-    t.test('arrayFormat: indices allows only indexed arrays', function (st) {
-        st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'indices' }), { a: 'b,c' });
-        st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
+    t.test('comma: true', function (st) {
+        st.deepEqual(qs.parse('a[]=b&a[]=c', { comma: true }), { a: ['b', 'c'] });
+        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { comma: true }), { a: ['b', 'c'] });
+        st.deepEqual(qs.parse('a=b,c', { comma: true }), { a: ['b', 'c'] });
+        st.deepEqual(qs.parse('a=b&a=c', { comma: true }), { a: ['b', 'c'] });
         st.end();
     });
 
-    t.test('arrayFormat: comma allows only comma-separated arrays', function (st) {
-        st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'comma' }), { a: 'b,c' });
-        st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
+    t.test('allows enabling dot notation', function (st) {
+        st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
+        st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
+
         st.end();
     });
 
-    t.test('arrayFormat: repeat allows only repeated values', function (st) {
-        st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
-        st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'repeat' }), { a: 'b,c' });
-        st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
+    t.test('decode dot keys correctly', function (st) {
+        st.deepEqual(
+            qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: false, decodeDotInKeys: false }),
+            { 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' },
+            'with allowDots false and decodeDotInKeys false'
+        );
+        st.deepEqual(
+            qs.parse('name.obj.first=John&name.obj.last=Doe', { allowDots: true, decodeDotInKeys: false }),
+            { name: { obj: { first: 'John', last: 'Doe' } } },
+            'with allowDots false and decodeDotInKeys false'
+        );
+        st.deepEqual(
+            qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: true, decodeDotInKeys: false }),
+            { 'name%2Eobj': { first: 'John', last: 'Doe' } },
+            'with allowDots true and decodeDotInKeys false'
+        );
+        st.deepEqual(
+            qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: true, decodeDotInKeys: true }),
+            { 'name.obj': { first: 'John', last: 'Doe' } },
+            'with allowDots true and decodeDotInKeys true'
+        );
+
+        st.deepEqual(
+            qs.parse(
+                'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
+                { allowDots: false, decodeDotInKeys: false }
+            ),
+            { 'name%2Eobj%2Esubobject.first%2Egodly%2Ename': 'John', 'name%2Eobj%2Esubobject.last': 'Doe' },
+            'with allowDots false and decodeDotInKeys false'
+        );
+        st.deepEqual(
+            qs.parse(
+                'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
+                { allowDots: true, decodeDotInKeys: false }
+            ),
+            { name: { obj: { subobject: { first: { godly: { name: 'John' } }, last: 'Doe' } } } },
+            'with allowDots true and decodeDotInKeys false'
+        );
+        st.deepEqual(
+            qs.parse(
+                'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
+                { allowDots: true, decodeDotInKeys: true }
+            ),
+            { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
+            'with allowDots true and decodeDotInKeys true'
+        );
+        st.deepEqual(
+            qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe'),
+            { 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' },
+            'with allowDots and decodeDotInKeys undefined'
+        );
+
         st.end();
     });
 
-    t.test('allows enabling dot notation', function (st) {
-        st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
-        st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
+    t.test('should decode dot in key of object, and allow enabling dot notation when decodeDotInKeys is set to true and allowDots is undefined', function (st) {
+        st.deepEqual(
+            qs.parse(
+                'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
+                { decodeDotInKeys: true }
+            ),
+            { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
+            'with allowDots undefined and decodeDotInKeys true'
+        );
+
+        st.end();
+    });
+
+    t.test('should throw when decodeDotInKeys is not of type boolean', function (st) {
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 'foobar' }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 0 }); },
+            TypeError
+        );
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: NaN }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: null }); },
+            TypeError
+        );
+
+        st.end();
+    });
+
+    t.test('allows empty arrays in obj values', function (st) {
+        st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: true }), { foo: [], bar: 'baz' });
+        st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: false }), { foo: [''], bar: 'baz' });
+
+        st.end();
+    });
+
+    t.test('should throw when allowEmptyArrays is not of type boolean', function (st) {
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: 'foobar' }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: 0 }); },
+            TypeError
+        );
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: NaN }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: null }); },
+            TypeError
+        );
+
+        st.end();
+    });
+
+    t.test('allowEmptyArrays + strictNullHandling', function (st) {
+        st.deepEqual(
+            qs.parse('testEmptyArray[]', { strictNullHandling: true, allowEmptyArrays: true }),
+            { testEmptyArray: [] }
+        );
+
         st.end();
     });
 
@@ -140,6 +262,9 @@ test('parse()', function (t) {
     t.test('limits specific array indices to arrayLimit', function (st) {
         st.deepEqual(qs.parse('a[20]=a', { arrayLimit: 20 }), { a: ['a'] });
         st.deepEqual(qs.parse('a[21]=a', { arrayLimit: 20 }), { a: { 21: 'a' } });
+
+        st.deepEqual(qs.parse('a[20]=a'), { a: ['a'] });
+        st.deepEqual(qs.parse('a[21]=a'), { a: { 21: 'a' } });
         st.end();
     });
 
@@ -319,14 +444,14 @@ test('parse()', function (t) {
     });
 
     t.test('should not throw when a native prototype has an enumerable property', function (st) {
-        Object.prototype.crash = '';
-        Array.prototype.crash = '';
+        st.intercept(Object.prototype, 'crash', { value: '' });
+        st.intercept(Array.prototype, 'crash', { value: '' });
+
         st.doesNotThrow(qs.parse.bind(null, 'a=b'));
         st.deepEqual(qs.parse('a=b'), { a: 'b' });
         st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c'));
         st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] });
-        delete Object.prototype.crash;
-        delete Array.prototype.crash;
+
         st.end();
     });
 
@@ -357,8 +482,14 @@ test('parse()', function (t) {
 
     t.test('allows overriding array limit', function (st) {
         st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } });
+        st.deepEqual(qs.parse('a[0]=b', { arrayLimit: 0 }), { a: ['b'] });
+
         st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } });
+        st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: 0 }), { a: { '-1': 'b' } });
+
+        st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: -1 }), { a: { 0: 'b', 1: 'c' } });
         st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } });
+
         st.end();
     });
 
@@ -378,6 +509,7 @@ test('parse()', function (t) {
         st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
         st.deepEqual(qs.parse('foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
         st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: false }), { '?foo': 'bar' });
+
         st.end();
     });
 
@@ -406,6 +538,16 @@ test('parse()', function (t) {
         st.deepEqual(qs.parse('foo=', { comma: true }), { foo: '' });
         st.deepEqual(qs.parse('foo', { comma: true }), { foo: '' });
         st.deepEqual(qs.parse('foo', { comma: true, strictNullHandling: true }), { foo: null });
+
+        // test cases inversed from from stringify tests
+        st.deepEqual(qs.parse('a[0]=c'), { a: ['c'] });
+        st.deepEqual(qs.parse('a[]=c'), { a: ['c'] });
+        st.deepEqual(qs.parse('a[]=c', { comma: true }), { a: ['c'] });
+
+        st.deepEqual(qs.parse('a[0]=c&a[1]=d'), { a: ['c', 'd'] });
+        st.deepEqual(qs.parse('a[]=c&a[]=d'), { a: ['c', 'd'] });
+        st.deepEqual(qs.parse('a=c,d', { comma: true }), { a: ['c', 'd'] });
+
         st.end();
     });
 
@@ -438,6 +580,15 @@ test('parse()', function (t) {
         st.end();
     });
 
+    t.test('parses url-encoded brackets holds array of arrays when having two parts of strings with comma as array divider', function (st) {
+        st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=4,5,6', { comma: true }), { foo: [['1', '2', '3'], ['4', '5', '6']] });
+        st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=', { comma: true }), { foo: [['1', '2', '3'], ''] });
+        st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=,', { comma: true }), { foo: [['1', '2', '3'], ['', '']] });
+        st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=a', { comma: true }), { foo: [['1', '2', '3'], 'a'] });
+
+        st.end();
+    });
+
     t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) {
         st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' });
         st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] });
@@ -485,10 +636,12 @@ test('parse()', function (t) {
     });
 
     t.test('does not blow up when Buffer global is missing', function (st) {
-        var tempBuffer = global.Buffer;
-        delete global.Buffer;
+        var restore = mockProperty(global, 'Buffer', { 'delete': true });
+
         var result = qs.parse('a=b&c=d');
-        global.Buffer = tempBuffer;
+
+        restore();
+
         st.deepEqual(result, { a: 'b', c: 'd' });
         st.end();
     });
@@ -587,6 +740,34 @@ test('parse()', function (t) {
         st.end();
     });
 
+    t.test('does not crash when the global Object prototype is frozen', { skip: !hasPropertyDescriptors || !hasOverrideMistake }, function (st) {
+        // We can't actually freeze the global Object prototype as that will interfere with other tests, and once an object is frozen, it
+        // can't be unfrozen. Instead, we add a new non-writable property to simulate this.
+        st.teardown(mockProperty(Object.prototype, 'frozenProp', { value: 'foo', nonWritable: true, nonEnumerable: true }));
+
+        st['throws'](
+            function () {
+                var obj = {};
+                obj.frozenProp = 'bar';
+            },
+            // node < 6 has a different error message
+            /^TypeError: Cannot assign to read only property 'frozenProp' of (?:object '#<Object>'|#<Object>)/,
+            'regular assignment of an inherited non-writable property throws'
+        );
+
+        var parsed;
+        st.doesNotThrow(
+            function () {
+                parsed = qs.parse('frozenProp', { allowPrototypes: false });
+            },
+            'parsing a nonwritable Object.prototype property does not throw'
+        );
+
+        st.deepEqual(parsed, {}, 'bare "frozenProp" results in {}');
+
+        st.end();
+    });
+
     t.test('params starting with a closing bracket', function (st) {
         st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
         st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });
@@ -839,3 +1020,151 @@ test('parse()', function (t) {
 
     t.end();
 });
+
+test('parses empty keys', function (t) {
+    emptyTestCases.forEach(function (testCase) {
+        t.test('skips empty string key with ' + testCase.input, function (st) {
+            st.deepEqual(qs.parse(testCase.input), testCase.noEmptyKeys);
+
+            st.end();
+        });
+    });
+});
+
+test('`duplicates` option', function (t) {
+    v.nonStrings.concat('not a valid option').forEach(function (invalidOption) {
+        if (typeof invalidOption !== 'undefined') {
+            t['throws'](
+                function () { qs.parse('', { duplicates: invalidOption }); },
+                TypeError,
+                'throws on invalid option: ' + inspect(invalidOption)
+            );
+        }
+    });
+
+    t.deepEqual(
+        qs.parse('foo=bar&foo=baz'),
+        { foo: ['bar', 'baz'] },
+        'duplicates: default, combine'
+    );
+
+    t.deepEqual(
+        qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }),
+        { foo: ['bar', 'baz'] },
+        'duplicates: combine'
+    );
+
+    t.deepEqual(
+        qs.parse('foo=bar&foo=baz', { duplicates: 'first' }),
+        { foo: 'bar' },
+        'duplicates: first'
+    );
+
+    t.deepEqual(
+        qs.parse('foo=bar&foo=baz', { duplicates: 'last' }),
+        { foo: 'baz' },
+        'duplicates: last'
+    );
+
+    t.end();
+});
+
+test('qs strictDepth option - throw cases', function (t) {
+    t.test('throws an exception when depth exceeds the limit with strictDepth: true', function (st) {
+        st['throws'](
+            function () {
+                qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1, strictDepth: true });
+            },
+            RangeError,
+            'Should throw RangeError'
+        );
+        st.end();
+    });
+
+    t.test('throws an exception for multiple nested arrays with strictDepth: true', function (st) {
+        st['throws'](
+            function () {
+                qs.parse('a[0][1][2][3][4]=b', { depth: 3, strictDepth: true });
+            },
+            RangeError,
+            'Should throw RangeError'
+        );
+        st.end();
+    });
+
+    t.test('throws an exception for nested objects and arrays with strictDepth: true', function (st) {
+        st['throws'](
+            function () {
+                qs.parse('a[b][c][0][d][e]=f', { depth: 3, strictDepth: true });
+            },
+            RangeError,
+            'Should throw RangeError'
+        );
+        st.end();
+    });
+
+    t.test('throws an exception for different types of values with strictDepth: true', function (st) {
+        st['throws'](
+            function () {
+                qs.parse('a[b][c][d][e]=true&a[b][c][d][f]=42', { depth: 3, strictDepth: true });
+            },
+            RangeError,
+            'Should throw RangeError'
+        );
+        st.end();
+    });
+
+});
+
+test('qs strictDepth option - non-throw cases', function (t) {
+    t.test('when depth is 0 and strictDepth true, do not throw', function (st) {
+        st.doesNotThrow(
+            function () {
+                qs.parse('a[b][c][d][e]=true&a[b][c][d][f]=42', { depth: 0, strictDepth: true });
+            },
+            RangeError,
+            'Should not throw RangeError'
+        );
+        st.end();
+    });
+
+    t.test('parses successfully when depth is within the limit with strictDepth: true', function (st) {
+        st.doesNotThrow(
+            function () {
+                var result = qs.parse('a[b]=c', { depth: 1, strictDepth: true });
+                st.deepEqual(result, { a: { b: 'c' } }, 'Should parse correctly');
+            }
+        );
+        st.end();
+    });
+
+    t.test('does not throw an exception when depth exceeds the limit with strictDepth: false', function (st) {
+        st.doesNotThrow(
+            function () {
+                var result = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
+                st.deepEqual(result, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }, 'Should parse with depth limit');
+            }
+        );
+        st.end();
+    });
+
+    t.test('parses successfully when depth is within the limit with strictDepth: false', function (st) {
+        st.doesNotThrow(
+            function () {
+                var result = qs.parse('a[b]=c', { depth: 1 });
+                st.deepEqual(result, { a: { b: 'c' } }, 'Should parse correctly');
+            }
+        );
+        st.end();
+    });
+
+    t.test('does not throw when depth is exactly at the limit with strictDepth: true', function (st) {
+        st.doesNotThrow(
+            function () {
+                var result = qs.parse('a[b][c]=d', { depth: 2, strictDepth: true });
+                st.deepEqual(result, { a: { b: { c: 'd' } } }, 'Should parse correctly');
+            }
+        );
+        st.end();
+    });
+});

+ 490 - 57
express-server/node_modules/qs/test/stringify.js

@@ -6,6 +6,8 @@ var utils = require('../lib/utils');
 var iconv = require('iconv-lite');
 var SaferBuffer = require('safer-buffer').Buffer;
 var hasSymbols = require('has-symbols');
+var mockProperty = require('mock-property');
+var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
 var hasBigInt = typeof BigInt === 'function';
 
 test('stringify()', function (t) {
@@ -63,6 +65,138 @@ test('stringify()', function (t) {
         st.end();
     });
 
+    t.test('encodes dot in key of object when encodeDotInKeys and allowDots is provided', function (st) {
+        st.equal(
+            qs.stringify(
+                { 'name.obj': { first: 'John', last: 'Doe' } },
+                { allowDots: false, encodeDotInKeys: false }
+            ),
+            'name.obj%5Bfirst%5D=John&name.obj%5Blast%5D=Doe',
+            'with allowDots false and encodeDotInKeys false'
+        );
+        st.equal(
+            qs.stringify(
+                { 'name.obj': { first: 'John', last: 'Doe' } },
+                { allowDots: true, encodeDotInKeys: false }
+            ),
+            'name.obj.first=John&name.obj.last=Doe',
+            'with allowDots true and encodeDotInKeys false'
+        );
+        st.equal(
+            qs.stringify(
+                { 'name.obj': { first: 'John', last: 'Doe' } },
+                { allowDots: false, encodeDotInKeys: true }
+            ),
+            'name%252Eobj%5Bfirst%5D=John&name%252Eobj%5Blast%5D=Doe',
+            'with allowDots false and encodeDotInKeys true'
+        );
+        st.equal(
+            qs.stringify(
+                { 'name.obj': { first: 'John', last: 'Doe' } },
+                { allowDots: true, encodeDotInKeys: true }
+            ),
+            'name%252Eobj.first=John&name%252Eobj.last=Doe',
+            'with allowDots true and encodeDotInKeys true'
+        );
+
+        st.equal(
+            qs.stringify(
+                { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
+                { allowDots: false, encodeDotInKeys: false }
+            ),
+            'name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe',
+            'with allowDots false and encodeDotInKeys false'
+        );
+        st.equal(
+            qs.stringify(
+                { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
+                { allowDots: true, encodeDotInKeys: false }
+            ),
+            'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
+            'with allowDots false and encodeDotInKeys false'
+        );
+        st.equal(
+            qs.stringify(
+                { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
+                { allowDots: false, encodeDotInKeys: true }
+            ),
+            'name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe',
+            'with allowDots false and encodeDotInKeys true'
+        );
+        st.equal(
+            qs.stringify(
+                { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
+                { allowDots: true, encodeDotInKeys: true }
+            ),
+            'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
+            'with allowDots true and encodeDotInKeys true'
+        );
+
+        st.end();
+    });
+
+    t.test('should encode dot in key of object, and automatically set allowDots to `true` when encodeDotInKeys is true and allowDots in undefined', function (st) {
+        st.equal(
+            qs.stringify(
+                { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
+                { encodeDotInKeys: true }
+            ),
+            'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
+            'with allowDots undefined and encodeDotInKeys true'
+        );
+        st.end();
+    });
+
+    t.test('should encode dot in key of object when encodeDotInKeys and allowDots is provided, and nothing else when encodeValuesOnly is provided', function (st) {
+        st.equal(
+            qs.stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, {
+                encodeDotInKeys: true, allowDots: true, encodeValuesOnly: true
+            }),
+            'name%2Eobj.first=John&name%2Eobj.last=Doe'
+        );
+
+        st.equal(
+            qs.stringify({ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true }),
+            'name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe'
+        );
+
+        st.end();
+    });
+
+    t.test('throws when `commaRoundTrip` is not a boolean', function (st) {
+        st['throws'](
+            function () { qs.stringify({}, { commaRoundTrip: 'not a boolean' }); },
+            TypeError,
+            'throws when `commaRoundTrip` is not a boolean'
+        );
+
+        st.end();
+    });
+
+    t.test('throws when `encodeDotInKeys` is not a boolean', function (st) {
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null }); },
+            TypeError
+        );
+
+        st.end();
+    });
+
     t.test('adds query prefix', function (st) {
         st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
         st.end();
@@ -86,7 +220,7 @@ test('stringify()', function (t) {
         st.end();
     });
 
-    t.test('stringifies a nested object with dots notation', function (st) {
+    t.test('`allowDots` option: stringifies a nested object with dots notation', function (st) {
         st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
         st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
         st.end();
@@ -108,6 +242,11 @@ test('stringify()', function (t) {
             'a=b%2Cc%2Cd',
             'comma => comma'
         );
+        st.equal(
+            qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true }),
+            'a=b%2Cc%2Cd',
+            'comma round trip => comma'
+        );
         st.equal(
             qs.stringify({ a: ['b', 'c', 'd'] }),
             'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
@@ -116,18 +255,118 @@ test('stringify()', function (t) {
         st.end();
     });
 
-    t.test('omits nulls when asked', function (st) {
-        st.equal(qs.stringify({ a: 'b', c: null }, { skipNulls: true }), 'a=b');
-        st.end();
-    });
+    t.test('`skipNulls` option', function (st) {
+        st.equal(
+            qs.stringify({ a: 'b', c: null }, { skipNulls: true }),
+            'a=b',
+            'omits nulls when asked'
+        );
+
+        st.equal(
+            qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }),
+            'a%5Bb%5D=c',
+            'omits nested nulls when asked'
+        );
 
-    t.test('omits nested nulls when asked', function (st) {
-        st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c');
         st.end();
     });
 
     t.test('omits array indices when asked', function (st) {
         st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d');
+
+        st.end();
+    });
+
+    t.test('omits object key/value pair when value is empty array', function (st) {
+        st.equal(qs.stringify({ a: [], b: 'zz' }), 'b=zz');
+
+        st.end();
+    });
+
+    t.test('should not omit object key/value pair when value is empty array and when asked', function (st) {
+        st.equal(qs.stringify({ a: [], b: 'zz' }), 'b=zz');
+        st.equal(qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false }), 'b=zz');
+        st.equal(qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true }), 'a[]&b=zz');
+
+        st.end();
+    });
+
+    t.test('should throw when allowEmptyArrays is not of type boolean', function (st) {
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN }); },
+            TypeError
+        );
+
+        st['throws'](
+            function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null }); },
+            TypeError
+        );
+
+        st.end();
+    });
+
+    t.test('allowEmptyArrays + strictNullHandling', function (st) {
+        st.equal(
+            qs.stringify(
+                { testEmptyArray: [] },
+                { strictNullHandling: true, allowEmptyArrays: true }
+            ),
+            'testEmptyArray[]'
+        );
+
+        st.end();
+    });
+
+    t.test('stringifies an array value with one item vs multiple items', function (st) {
+        st.test('non-array item', function (s2t) {
+            s2t.equal(qs.stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a=c');
+            s2t.equal(qs.stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a=c');
+            s2t.equal(qs.stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c');
+            s2t.equal(qs.stringify({ a: 'c' }, { encodeValuesOnly: true }), 'a=c');
+
+            s2t.end();
+        });
+
+        st.test('array with a single item', function (s2t) {
+            s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=c');
+            s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=c');
+            s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c');
+            s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a[]=c'); // so it parses back as an array
+            s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true }), 'a[0]=c');
+
+            s2t.end();
+        });
+
+        st.test('array with multiple items', function (s2t) {
+            s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=c&a[1]=d');
+            s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=c&a[]=d');
+            s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c,d');
+            s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a=c,d');
+            s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true }), 'a[0]=c&a[1]=d');
+
+            s2t.end();
+        });
+
+        st.test('array with multiple items with a comma inside', function (s2t) {
+            s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c%2Cd,e');
+            s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%2Cd%2Ce');
+
+            s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a=c%2Cd,e');
+            s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true }), 'a=c%2Cd%2Ce');
+
+            s2t.end();
+        });
+
         st.end();
     });
 
@@ -139,6 +378,44 @@ test('stringify()', function (t) {
         st.end();
     });
 
+    t.test('stringifies comma and empty array values', function (st) {
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' }), 'a[0]=,&a[1]=&a[2]=c,d%');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' }), 'a[]=,&a[]=&a[]=c,d%');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' }), 'a=,,,c,d%');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' }), 'a=,&a=&a=c,d%');
+
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=%2C&a[1]=&a[2]=c%2Cd%25');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=%2C&a[]=&a[]=c%2Cd%25');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=%2C,,c%2Cd%25');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=%2C&a=&a=c%2Cd%25');
+
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), 'a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }), 'a%5B%5D=%2C&a%5B%5D=&a%5B%5D=c%2Cd%25');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), 'a=%2C%2C%2Cc%2Cd%25');
+        st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), 'a=%2C&a=&a=c%2Cd%25');
+
+        st.end();
+    });
+
+    t.test('stringifies comma and empty non-array values', function (st) {
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' }), 'a=,&b=&c=c,d%');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' }), 'a=,&b=&c=c,d%');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'comma' }), 'a=,&b=&c=c,d%');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'repeat' }), 'a=,&b=&c=c,d%');
+
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }), 'a=%2C&b=&c=c%2Cd%25');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a=%2C&b=&c=c%2Cd%25');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=%2C&b=&c=c%2Cd%25');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=%2C&b=&c=c%2Cd%25');
+
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), 'a=%2C&b=&c=c%2Cd%25');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }), 'a=%2C&b=&c=c%2Cd%25');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), 'a=%2C&b=&c=c%2Cd%25');
+        st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), 'a=%2C&b=&c=c%2Cd%25');
+
+        st.end();
+    });
+
     t.test('stringifies a nested array value with dots notation', function (st) {
         st.equal(
             qs.stringify(
@@ -177,36 +454,44 @@ test('stringify()', function (t) {
 
     t.test('stringifies an object inside an array', function (st) {
         st.equal(
-            qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices' }),
-            'a%5B0%5D%5Bb%5D=c', // a[0][b]=c
-            'indices => brackets'
+            qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
+            'a[0][b]=c',
+            'indices => indices'
+        );
+        st.equal(
+            qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
+            'a[b]=c',
+            'repeat => repeat'
         );
         st.equal(
-            qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets' }),
-            'a%5B%5D%5Bb%5D=c', // a[][b]=c
+            qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
+            'a[][b]=c',
             'brackets => brackets'
         );
         st.equal(
-            qs.stringify({ a: [{ b: 'c' }] }),
-            'a%5B0%5D%5Bb%5D=c',
+            qs.stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true }),
+            'a[0][b]=c',
             'default => indices'
         );
 
         st.equal(
-            qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices' }),
-            'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
+            qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
+            'a[0][b][c][0]=1',
             'indices => indices'
         );
-
         st.equal(
-            qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets' }),
-            'a%5B%5D%5Bb%5D%5Bc%5D%5B%5D=1',
+            qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
+            'a[b][c]=1',
+            'repeat => repeat'
+        );
+        st.equal(
+            qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
+            'a[][b][c][]=1',
             'brackets => brackets'
         );
-
         st.equal(
-            qs.stringify({ a: [{ b: { c: [1] } }] }),
-            'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
+            qs.stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true }),
+            'a[0][b][c][0]=1',
             'default => indices'
         );
 
@@ -308,17 +593,17 @@ test('stringify()', function (t) {
         st.end();
     });
 
-    t.test('uses indices notation for arrays when no arrayFormat=indices', function (st) {
+    t.test('uses indices notation for arrays when arrayFormat=indices', function (st) {
         st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c');
         st.end();
     });
 
-    t.test('uses repeat notation for arrays when no arrayFormat=repeat', function (st) {
+    t.test('uses repeat notation for arrays when arrayFormat=repeat', function (st) {
         st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c');
         st.end();
     });
 
-    t.test('uses brackets notation for arrays when no arrayFormat=brackets', function (st) {
+    t.test('uses brackets notation for arrays when arrayFormat=brackets', function (st) {
         st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c');
         st.end();
     });
@@ -349,11 +634,13 @@ test('stringify()', function (t) {
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' }), 'b[]=&c=c');
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' }), 'b=&c=c');
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' }), 'b=&c=c');
+        st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', commaRoundTrip: true }), 'b[]=&c=c');
         // with strictNullHandling
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', strictNullHandling: true }), 'b[0]&c=c');
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', strictNullHandling: true }), 'b[]&c=c');
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat', strictNullHandling: true }), 'b&c=c');
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', strictNullHandling: true }), 'b&c=c');
+        st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true }), 'b[]&c=c');
         // with skipNulls
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', skipNulls: true }), 'c=c');
         st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', skipNulls: true }), 'c=c');
@@ -413,10 +700,11 @@ test('stringify()', function (t) {
     });
 
     t.test('skips properties that are part of the object prototype', function (st) {
-        Object.prototype.crash = 'test';
+        st.intercept(Object.prototype, 'crash', { value: 'test' });
+
         st.equal(qs.stringify({ a: 'b' }), 'a=b');
         st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
-        delete Object.prototype.crash;
+
         st.end();
     });
 
@@ -440,10 +728,12 @@ test('stringify()', function (t) {
     });
 
     t.test('does not blow up when Buffer global is missing', function (st) {
-        var tempBuffer = global.Buffer;
-        delete global.Buffer;
+        var restore = mockProperty(global, 'Buffer', { 'delete': true });
+
         var result = qs.stringify({ a: 'b', c: 'd' });
-        global.Buffer = tempBuffer;
+
+        restore();
+
         st.equal(result, 'a=b&c=d');
         st.end();
     });
@@ -492,9 +782,17 @@ test('stringify()', function (t) {
         };
 
         st.equal(
-            qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true }),
+            qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
             'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23'
         );
+        st.equal(
+            qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
+            'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23'
+        );
+        st.equal(
+            qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
+            'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23'
+        );
 
         st.end();
     });
@@ -607,13 +905,28 @@ test('stringify()', function (t) {
         st.end();
     });
 
+    t.test('receives the default encoder as a second argument', function (st) {
+        st.plan(8);
+
+        qs.stringify({ a: 1, b: new Date(), c: true, d: [1] }, {
+            encoder: function (str) {
+                st.match(typeof str, /^(?:string|number|boolean)$/);
+                return '';
+            }
+        });
+
+        st.end();
+    });
+
     t.test('receives the default encoder as a second argument', function (st) {
         st.plan(2);
+
         qs.stringify({ a: 1 }, {
             encoder: function (str, defaultEncoder) {
                 st.equal(defaultEncoder, utils.encode);
             }
         });
+
         st.end();
     });
 
@@ -684,6 +997,18 @@ test('stringify()', function (t) {
             'a=' + date.getTime(),
             'works with arrayFormat comma'
         );
+        st.equal(
+            qs.stringify(
+                { a: [date] },
+                {
+                    serializeDate: function (d) { return d.getTime(); },
+                    arrayFormat: 'comma',
+                    commaRoundTrip: true
+                }
+            ),
+            'a%5B%5D=' + date.getTime(),
+            'works with arrayFormat comma'
+        );
 
         st.end();
     });
@@ -714,16 +1039,14 @@ test('stringify()', function (t) {
     });
 
     t.test('Edge cases and unknown formats', function (st) {
-        ['UFO1234', false, 1234, null, {}, []].forEach(
-            function (format) {
-                st['throws'](
-                    function () {
-                        qs.stringify({ a: 'b c' }, { format: format });
-                    },
-                    new TypeError('Unknown format option provided.')
-                );
-            }
-        );
+        ['UFO1234', false, 1234, null, {}, []].forEach(function (format) {
+            st['throws'](
+                function () {
+                    qs.stringify({ a: 'b c' }, { format: format });
+                },
+                new TypeError('Unknown format option provided.')
+            );
+        });
         st.end();
     });
 
@@ -731,16 +1054,53 @@ test('stringify()', function (t) {
         st.equal(
             qs.stringify(
                 { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
-                { encodeValuesOnly: true }
+                { encodeValuesOnly: true, arrayFormat: 'indices' }
             ),
-            'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
+            'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h',
+            'encodeValuesOnly + indices'
         );
         st.equal(
             qs.stringify(
-                { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }
+                { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
+                { encodeValuesOnly: true, arrayFormat: 'brackets' }
+            ),
+            'a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h',
+            'encodeValuesOnly + brackets'
+        );
+        st.equal(
+            qs.stringify(
+                { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
+                { encodeValuesOnly: true, arrayFormat: 'repeat' }
             ),
-            'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h'
+            'a=b&c=d&c=e%3Df&f=g&f=h',
+            'encodeValuesOnly + repeat'
         );
+
+        st.equal(
+            qs.stringify(
+                { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
+                { arrayFormat: 'indices' }
+            ),
+            'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h',
+            'no encodeValuesOnly + indices'
+        );
+        st.equal(
+            qs.stringify(
+                { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
+                { arrayFormat: 'brackets' }
+            ),
+            'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h',
+            'no encodeValuesOnly + brackets'
+        );
+        st.equal(
+            qs.stringify(
+                { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
+                { arrayFormat: 'repeat' }
+            ),
+            'a=b&c=d&c=e&f=g&f=h',
+            'no encodeValuesOnly + repeat'
+        );
+
         st.end();
     });
 
@@ -777,13 +1137,19 @@ test('stringify()', function (t) {
         st.end();
     });
 
-    t.test('adds the right sentinel when instructed to and the charset is utf-8', function (st) {
-        st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }), 'utf8=%E2%9C%93&a=%C3%A6');
-        st.end();
-    });
+    t.test('`charsetSentinel` option', function (st) {
+        st.equal(
+            qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }),
+            'utf8=%E2%9C%93&a=%C3%A6',
+            'adds the right sentinel when instructed to and the charset is utf-8'
+        );
+
+        st.equal(
+            qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }),
+            'utf8=%26%2310003%3B&a=%E6',
+            'adds the right sentinel when instructed to and the charset is iso-8859-1'
+        );
 
-    t.test('adds the right sentinel when instructed to and the charset is iso-8859-1', function (st) {
-        st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }), 'utf8=%26%2310003%3B&a=%E6');
         st.end();
     });
 
@@ -834,13 +1200,15 @@ test('stringify()', function (t) {
         var withArray = { a: { b: [{ c: 'd', e: 'f' }] } };
 
         st.equal(qs.stringify(obj, { encode: false }), 'a[b][c]=d&a[b][e]=f', 'no array, no arrayFormat');
-        st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'bracket' }), 'a[b][c]=d&a[b][e]=f', 'no array, bracket');
+        st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'brackets' }), 'a[b][c]=d&a[b][e]=f', 'no array, bracket');
         st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'indices' }), 'a[b][c]=d&a[b][e]=f', 'no array, indices');
+        st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'repeat' }), 'a[b][c]=d&a[b][e]=f', 'no array, repeat');
         st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'comma' }), 'a[b][c]=d&a[b][e]=f', 'no array, comma');
 
         st.equal(qs.stringify(withArray, { encode: false }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, no arrayFormat');
-        st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'bracket' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, bracket');
+        st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'brackets' }), 'a[b][][c]=d&a[b][][e]=f', 'array, bracket');
         st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'indices' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, indices');
+        st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'repeat' }), 'a[b][c]=d&a[b][e]=f', 'array, repeat');
         st.equal(
             qs.stringify(withArray, { encode: false, arrayFormat: 'comma' }),
             '???',
@@ -853,13 +1221,78 @@ test('stringify()', function (t) {
 
     t.test('stringifies sparse arrays', function (st) {
         /* eslint no-sparse-arrays: 0 */
-        st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true }), 'a[1]=2&a[4]=1');
-        st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true }), 'a[1][b][2][c]=1');
-        st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true }), 'a[1][2][3][c]=1');
-        st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true }), 'a[1][2][3][c][1]=1');
+        st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1]=2&a[4]=1');
+        st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=2&a[]=1');
+        st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=2&a=1');
+
+        st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][b][2][c]=1');
+        st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][b][][c]=1');
+        st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[b][c]=1');
+
+        st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][2][3][c]=1');
+        st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][][][c]=1');
+        st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[c]=1');
+
+        st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][2][3][c][1]=1');
+        st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][][][c][]=1');
+        st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[c]=1');
+
+        st.end();
+    });
+
+    t.test('encodes a very long string', function (st) {
+        var chars = [];
+        var expected = [];
+        for (var i = 0; i < 5e3; i++) {
+            chars.push(' ' + i);
+
+            expected.push('%20' + i);
+        }
+
+        var obj = {
+            foo: chars.join('')
+        };
+
+        st.equal(
+            qs.stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' }),
+            'foo=' + expected.join('')
+        );
 
         st.end();
     });
 
     t.end();
 });
+
+test('stringifies empty keys', function (t) {
+    emptyTestCases.forEach(function (testCase) {
+        t.test('stringifies an object with empty string key with ' + testCase.input, function (st) {
+            st.deepEqual(
+                qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'indices' }),
+                testCase.stringifyOutput.indices,
+                'test case: ' + testCase.input + ', indices'
+            );
+            st.deepEqual(
+                qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'brackets' }),
+                testCase.stringifyOutput.brackets,
+                'test case: ' + testCase.input + ', brackets'
+            );
+            st.deepEqual(
+                qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'repeat' }),
+                testCase.stringifyOutput.repeat,
+                'test case: ' + testCase.input + ', repeat'
+            );
+
+            st.end();
+        });
+    });
+
+    t.test('edge case with object/arrays', function (st) {
+        st.deepEqual(qs.stringify({ '': { '': [2, 3] } }, { encode: false }), '[][0]=2&[][1]=3');
+        st.deepEqual(qs.stringify({ '': { '': [2, 3], a: 2 } }, { encode: false }), '[][0]=2&[][1]=3&[a]=2');
+        st.deepEqual(qs.stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' }), '[][0]=2&[][1]=3');
+        st.deepEqual(qs.stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' }), '[][0]=2&[][1]=3&[a]=2');
+
+        st.end();
+    });
+});

+ 5 - 0
express-server/node_modules/raw-body/HISTORY.md

@@ -1,3 +1,8 @@
+2.5.2 / 2023-02-21
+==================
+
+  * Fix error message for non-stream argument
+
 2.5.1 / 2022-02-28
 ==================
 

+ 1 - 1
express-server/node_modules/raw-body/README.md

@@ -219,5 +219,5 @@ server.listen(3000);
 [coveralls-url]: https://coveralls.io/r/stream-utils/raw-body?branch=master
 [downloads-image]: https://img.shields.io/npm/dm/raw-body.svg
 [downloads-url]: https://npmjs.org/package/raw-body
-[github-actions-ci-image]: https://img.shields.io/github/workflow/status/stream-utils/raw-body/ci/master?label=ci
+[github-actions-ci-image]: https://img.shields.io/github/actions/workflow/status/stream-utils/raw-body/ci.yml?branch=master&label=ci
 [github-actions-ci-url]: https://github.com/jshttp/stream-utils/raw-body?query=workflow%3Aci

+ 7 - 0
express-server/node_modules/raw-body/index.js

@@ -69,6 +69,13 @@ function getRawBody (stream, options, callback) {
   var done = callback
   var opts = options || {}
 
+  // light validation
+  if (stream === undefined) {
+    throw new TypeError('argument stream is required')
+  } else if (typeof stream !== 'object' || stream === null || typeof stream.on !== 'function') {
+    throw new TypeError('argument stream must be a stream')
+  }
+
   if (options === true || typeof options === 'string') {
     // short cut for encoding
     opts = {

+ 17 - 18
express-server/node_modules/raw-body/package.json

@@ -1,27 +1,26 @@
 {
-  "_from": "raw-body@2.5.1",
-  "_id": "raw-body@2.5.1",
+  "_from": "raw-body@2.5.2",
+  "_id": "raw-body@2.5.2",
   "_inBundle": false,
-  "_integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+  "_integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
   "_location": "/raw-body",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "raw-body@2.5.1",
+    "raw": "raw-body@2.5.2",
     "name": "raw-body",
     "escapedName": "raw-body",
-    "rawSpec": "2.5.1",
+    "rawSpec": "2.5.2",
     "saveSpec": null,
-    "fetchSpec": "2.5.1"
+    "fetchSpec": "2.5.2"
   },
   "_requiredBy": [
-    "/body-parser",
-    "/pac-proxy-agent"
+    "/body-parser"
   ],
-  "_resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
-  "_shasum": "fe1b1628b181b700215e5fd42389f98b71392857",
-  "_spec": "raw-body@2.5.1",
+  "_resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+  "_shasum": "99febd83b90e08975087e8f1f9419a149366b68a",
+  "_spec": "raw-body@2.5.2",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\body-parser",
   "author": {
     "name": "Jonathan Ong",
@@ -52,14 +51,14 @@
   "description": "Get and validate the raw body of a readable stream.",
   "devDependencies": {
     "bluebird": "3.7.2",
-    "eslint": "7.32.0",
-    "eslint-config-standard": "14.1.1",
-    "eslint-plugin-import": "2.25.4",
-    "eslint-plugin-markdown": "2.2.1",
+    "eslint": "8.34.0",
+    "eslint-config-standard": "15.0.1",
+    "eslint-plugin-import": "2.27.5",
+    "eslint-plugin-markdown": "3.0.0",
     "eslint-plugin-node": "11.1.0",
-    "eslint-plugin-promise": "5.2.0",
+    "eslint-plugin-promise": "6.1.1",
     "eslint-plugin-standard": "4.1.0",
-    "mocha": "9.2.1",
+    "mocha": "10.2.0",
     "nyc": "15.1.0",
     "readable-stream": "2.3.7",
     "safe-buffer": "5.2.1"
@@ -88,5 +87,5 @@
     "test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
     "test-cov": "nyc --reporter=html --reporter=text npm test"
   },
-  "version": "2.5.1"
+  "version": "2.5.2"
 }

+ 2 - 5
express-server/node_modules/safe-buffer/package.json

@@ -16,16 +16,13 @@
     "fetchSpec": "5.2.1"
   },
   "_requiredBy": [
-    "/bl",
     "/content-disposition",
     "/ecdsa-sig-formatter",
     "/express",
+    "/express-session",
     "/jwa",
     "/jws",
-    "/minipass",
-    "/mongodb",
-    "/mongoose",
-    "/tar"
+    "/string_decoder"
   ],
   "_resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
   "_shasum": "1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6",

+ 5 - 0
express-server/node_modules/send/HISTORY.md

@@ -1,3 +1,8 @@
+0.19.0 / 2024-09-10
+===================
+
+* Remove link renderization in html while redirecting
+
 0.18.0 / 2022-03-23
 ===================
 

+ 1 - 2
express-server/node_modules/send/index.js

@@ -482,8 +482,7 @@ SendStream.prototype.redirect = function redirect (path) {
   }
 
   var loc = encodeUrl(collapseLeadingSlashes(this.path + '/'))
-  var doc = createHtmlDocument('Redirecting', 'Redirecting to <a href="' + escapeHtml(loc) + '">' +
-    escapeHtml(loc) + '</a>')
+  var doc = createHtmlDocument('Redirecting', 'Redirecting to ' + escapeHtml(loc))
 
   // redirect
   res.statusCode = 301

+ 10 - 10
express-server/node_modules/send/package.json

@@ -1,27 +1,27 @@
 {
-  "_from": "send@0.18.0",
-  "_id": "send@0.18.0",
+  "_from": "send@0.19.0",
+  "_id": "send@0.19.0",
   "_inBundle": false,
-  "_integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+  "_integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
   "_location": "/send",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "send@0.18.0",
+    "raw": "send@0.19.0",
     "name": "send",
     "escapedName": "send",
-    "rawSpec": "0.18.0",
+    "rawSpec": "0.19.0",
     "saveSpec": null,
-    "fetchSpec": "0.18.0"
+    "fetchSpec": "0.19.0"
   },
   "_requiredBy": [
     "/express",
     "/serve-static"
   ],
-  "_resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
-  "_shasum": "670167cc654b05f5aa4a767f9113bb371bc706be",
-  "_spec": "send@0.18.0",
+  "_resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+  "_shasum": "bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8",
+  "_spec": "send@0.19.0",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "author": {
     "name": "TJ Holowaychuk",
@@ -103,5 +103,5 @@
     "test-ci": "nyc --reporter=lcov --reporter=text npm test",
     "test-cov": "nyc --reporter=html --reporter=text npm test"
   },
-  "version": "0.18.0"
+  "version": "0.19.0"
 }

+ 16 - 0
express-server/node_modules/serve-static/HISTORY.md

@@ -1,3 +1,19 @@
+1.16.2 / 2024-09-11
+===================
+
+* deps: encodeurl@~2.0.0
+
+1.16.1 / 2024-09-11
+===================
+
+* deps: send@0.19.0
+
+1.16.0 / 2024-09-10
+===================
+
+* Remove link renderization in html while redirecting
+
+
 1.15.0 / 2022-03-24
 ===================
 

+ 12 - 12
express-server/node_modules/serve-static/package.json

@@ -1,26 +1,26 @@
 {
-  "_from": "serve-static@1.15.0",
-  "_id": "serve-static@1.15.0",
+  "_from": "serve-static@1.16.2",
+  "_id": "serve-static@1.16.2",
   "_inBundle": false,
-  "_integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+  "_integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
   "_location": "/serve-static",
   "_phantomChildren": {},
   "_requested": {
     "type": "version",
     "registry": true,
-    "raw": "serve-static@1.15.0",
+    "raw": "serve-static@1.16.2",
     "name": "serve-static",
     "escapedName": "serve-static",
-    "rawSpec": "1.15.0",
+    "rawSpec": "1.16.2",
     "saveSpec": null,
-    "fetchSpec": "1.15.0"
+    "fetchSpec": "1.16.2"
   },
   "_requiredBy": [
     "/express"
   ],
-  "_resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
-  "_shasum": "faaef08cffe0a1a62f60cad0c4e513cff0ac9540",
-  "_spec": "serve-static@1.15.0",
+  "_resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+  "_shasum": "b6a5343da47f6bdd2673848bf45754941e803296",
+  "_spec": "serve-static@1.16.2",
   "_where": "C:\\FatboarProject\\express-server\\node_modules\\express",
   "author": {
     "name": "Douglas Christopher Wilson",
@@ -31,10 +31,10 @@
   },
   "bundleDependencies": false,
   "dependencies": {
-    "encodeurl": "~1.0.2",
+    "encodeurl": "~2.0.0",
     "escape-html": "~1.0.3",
     "parseurl": "~1.3.3",
-    "send": "0.18.0"
+    "send": "0.19.0"
   },
   "deprecated": false,
   "description": "Serve static files",
@@ -73,5 +73,5 @@
     "test-cov": "nyc --reporter=html --reporter=text npm test",
     "version": "node scripts/version-history.js && git add HISTORY.md"
   },
-  "version": "1.15.0"
+  "version": "1.16.2"
 }

File diff suppressed because it is too large
+ 2262 - 991
express-server/package-lock.json


+ 7 - 6
express-server/package.json

@@ -16,9 +16,10 @@
   "dependencies": {
     "api-express-exporter": "^1.0.0",
     "bcrypt": "^5.0.1",
-    "body-parser": "^1.19.0",
+    "body-parser": "^1.20.2",
     "cors": "^2.8.5",
     "dayjs": "^1.8.29",
+    "dotenv": "^16.0.1",
     "express": "^4.17.1",
     "express-prom-bundle": "^6.1.0",
     "express-rate-limit": "^5.1.3",
@@ -26,16 +27,16 @@
     "jsonwebtoken": "^9.0.0",
     "mailgun-js": "^0.6.7",
     "mkdirp": "^1.0.4",
-    "moment": "^2.25.3",
-    "mongoose": "^5.9.6",
-    "mongoose-unique-validator": "^2.0.3",
+    "moment": "^2.29.4",
+    "mongoose": "^6.6.1",
+    "mongoose-unique-validator": "^2.0.1",
     "nodemailer": "^6.4.6",
-    "nodemon": "^2.0.2",
+    "nodemon": "^2.0.20",
     "passport": "^0.6.0",
     "passport-facebook": "^3.0.0",
     "passport-google-oauth20": "^2.0.0",
     "prom-client": "^12.0.0",
     "prometheus-api-metrics": "^2.2.7",
-    "validator": "^13.1.1"
+    "validator": "^13.7.0"
   }
 }