Skip to content
Snippets Groups Projects
Commit 605babd3 authored by Fredrik Fonn Hansen's avatar Fredrik Fonn Hansen :8ball:
Browse files

Merge branch 'fix-cypress' into 'main'

Fix cypress

See merge request !54
parents daf9c996 71f92e42
No related branches found
No related tags found
1 merge request!54Fix cypress
Pipeline #215489 passed
Showing
with 260 additions and 5220 deletions
describe('Game Test', () => {
const user1 = 'Cypress1' + Math.floor(Math.random() * 1000000);
const user2 = 'Cypress2' + Math.floor(Math.random() * 1000000);
const user3 = 'Cypress3' + Math.floor(Math.random() * 1000000);
const user1 = 'Cypress1';
const user2 = 'Cypress2';
const user3 = 'Cypress3';
const lobby = Math.floor(Math.random() * 1000);
let gameId = 0;
it('Can create a game', () => {
cy.genericRequest('GET', `/game/${lobby}`, 404, '');
cy.createUser(user1);
cy.createUser(user2);
cy.joinLobby(lobby, user1);
cy.joinLobby(lobby, user2);
cy.genericRequest('GET', `/game/${lobby}`, 200, '');
cy.genericRequest('POST', `/lobby/${lobby}/leave`, 200, { userId: user1 });
cy.genericRequest('POST', `/lobby/${lobby}/leave`, 200, { userId: user2 });
cy.deleteUser(user1);
cy.deleteUser(user2);
});
it('Can get currentTurn', () => {
cy.createUser(user1);
cy.createUser(user2);
cy.joinLobby(lobby, user1);
cy.joinLobby(lobby, user2);
cy.request({
method: 'GET',
url: `${Cypress.config('baseUrl')}/game/${lobby}`,
}).then((response) => {
expect(response.status).to.eq(200);
expect(response.body).to.not.be.empty;
const gameId = response.body;
});
cy.genericRequest('POST', `/lobby/${lobby}/leave`, 200, { userId: user1 });
cy.genericRequest('POST', `/lobby/${lobby}/leave`, 200, { userId: user2 });
cy.deleteUser(user1);
cy.deleteUser(user2);
});
it('Can send a valid move', () => {
let gameId = 0;
cy.createUser(user1);
cy.createUser(user2);
cy.joinLobby(lobby, user1);
cy.joinLobby(lobby, user2);
cy.request({
method: 'GET',
url: `${Cypress.config('baseUrl')}/game/${lobby}`,
......@@ -67,7 +47,7 @@ describe('Game Test', () => {
username: user1,
},
{
position: [0, 0],
position: 110,
turretAngle: 0,
health: 100,
ammunition: 100,
......@@ -86,7 +66,7 @@ describe('Game Test', () => {
username: user2,
},
{
position: [10, 0],
position: 910,
turretAngle: 30,
health: 100,
ammunition: 100,
......@@ -103,20 +83,9 @@ describe('Game Test', () => {
expect(response.status).to.eq(200);
});
});
cy.genericRequest('POST', `/lobby/${lobby}/leave`, 200, { userId: user1 });
cy.genericRequest('POST', `/lobby/${lobby}/leave`, 200, { userId: user2 });
cy.deleteUser(user1);
cy.deleteUser(user2);
});
it('Can send a invalid move', () => {
let gameId = 0;
cy.createUser(user1);
cy.createUser(user2);
cy.joinLobby(lobby, user1);
cy.joinLobby(lobby, user2);
it('Cant send a invalid move', () => {
cy.request({
method: 'GET',
url: `${Cypress.config('baseUrl')}/game/${lobby}`,
......@@ -171,7 +140,6 @@ describe('Game Test', () => {
],
};
cy.log(gameId.toString());
cy.request({
method: 'POST',
url: `${Cypress.config('baseUrl')}/game/${gameId}/move`,
......@@ -180,11 +148,8 @@ describe('Game Test', () => {
},
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(404);
expect(response.status).to.eq(400);
});
cy.deleteUser(user1);
cy.deleteUser(user2);
});
});
});
describe('Lobby Test', () => {
const user1 = 'Cypress1' + Math.floor(Math.random() * 1000000);
const user2 = 'Cypress2' + Math.floor(Math.random() * 1000000);
const user3 = 'Cypress3' + Math.floor(Math.random() * 1000000);
const user1 = 'Cypress1';
const user2 = 'Cypress2';
const user3 = 'Cypress3';
const lobby = Math.floor(Math.random() * 1000);
it('Creates a lobby and verifies its existence', () => {
const userId = 'testUserId';
// create two random users
// cy.deleteUser(user1);
// cy.deleteUser(user2);
cy.createUser(user1);
cy.createUser(user2);
cy.joinLobby(6969, user1);
cy.joinLobby(6969, user2);
// store the response in a variable
// cy.request('GET', `${Cypress.config('baseUrl')}/game/6969}`).as('todoResponse');
// const response = cy.getGameByLobbyId('6969');
// cy.request({
// method: 'GET',
// url: `${Cypress.config('baseUrl')}/game/${lobby}`,
// }).then((response) => {
// const gameId = response.body;
// expect(response.status).to.eq(200);
// });
// // Create a new lobby
// cy.request({
// method: 'POST',
// url: `${Cypress.config('baseUrl')}/lobby/6969?userId=${userId}`,
// }).then((response) => {
// expect(response.status).to.eq(201);
// const lobbyId = response.body;
const lobby2 = Math.floor(Math.random() * 1000);
// // Verify that the lobby exists
// cy.request({
// method: 'GET',
// url: `${Cypress.config('baseUrl')}/lobby/${lobbyId}`,
// }).then((response) => {
// expect(response.status).to.eq(200);
// expect(response.body).to.have.property('id', lobbyId);
// expect(response.body.users).to.include(userId);
// });
// });
cy.deleteUser(user1);
cy.deleteUser(user2);
});
it('Can join a lobby', () => {
cy.createUser(user1);
it('Creates a lobby and verifies its existence', () => {
cy.joinLobby(lobby, user1);
cy.deleteUser(user1);
});
it('Cannot join lobby twice', () => {
cy.createUser(user1);
cy.joinLobby(lobby, user1);
cy.genericRequest('POST', `/lobby/${lobby}/join`, 409, { userId: user1 });
cy.deleteUser(user1);
cy.genericRequest('POST', `/lobby/${lobby}/join`, 409, { username: user1 });
});
it('Only two users can join a lobby', () => {
cy.createUser(user1);
cy.createUser(user2);
cy.createUser(user3);
cy.joinLobby(lobby, user1);
cy.joinLobby(lobby, user2);
cy.genericRequest('POST', `/lobby/${lobby}/join`, 429, { userId: user3 });
cy.deleteUser(user1);
cy.deleteUser(user2);
cy.deleteUser(user3);
cy.genericRequest('POST', `/lobby/${lobby}/join`, 429, { username: user3 });
});
it('Can leave a lobby', () => {
const lobby2 = Math.floor(Math.random() * 1000);
cy.createUser(user1);
cy.genericRequest('POST', `/lobby/${lobby2}/join`, 201, { userId: user1 });
cy.genericRequest('POST', `/lobby/${lobby2}/leave`, 200, { userId: user1 });
cy.deleteUser(user1);
cy.genericRequest('POST', `/lobby/${lobby2}/leave`, 200, { username: user1 });
});
});
......@@ -7,24 +7,20 @@ describe('/user test', () => {
cy.createUser(username);
});
it('Can delete a user', () => {
cy.deleteUser(username);
});
it('Can find a user', () => {
cy.createUser(username);
cy.request({
method: 'GET',
url: `${Cypress.config('baseUrl')}/user/${username}`,
}).then((response) => {
expect(response.status).to.eq(200);
expect(response.body).to.have.property('username', username);
});
cy.deleteUser(username);
});
it('Can get a list of users', () => {
cy.genericRequest('GET', `/user/`, 200, '');
});
it('Can delete a user', () => {
cy.deleteUser(username);
});
});
......@@ -38,8 +38,8 @@
Cypress.Commands.add('deleteUser', (username: string) => {
cy.request({
method: 'POST',
url: `${Cypress.config('baseUrl')}/user/delete/${username}`,
method: 'DELETE',
url: `${Cypress.config('baseUrl')}/user/${username}`,
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.be.oneOf([204, 404]);
......@@ -49,7 +49,7 @@ Cypress.Commands.add('deleteUser', (username: string) => {
Cypress.Commands.add('createUser', (username: string) => {
cy.request({
method: 'POST',
url: `${Cypress.config('baseUrl')}/user/create/${username}`,
url: `${Cypress.config('baseUrl')}/user/${username}`,
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(201);
......@@ -66,13 +66,13 @@ Cypress.Commands.add('getUser', (username: string) => {
});
});
Cypress.Commands.add('joinLobby', (lobbyId: number, userId: string) => {
Cypress.Commands.add('joinLobby', (lobbyId: number, username: string) => {
cy.request({
method: 'POST',
url: `${Cypress.config('baseUrl')}/lobby/${lobbyId}/join`,
failOnStatusCode: false,
body: {
userId: userId,
username: username,
},
}).then((response) => {
expect(response.status).to.be.oneOf([200, 201, 409]);
......@@ -90,12 +90,12 @@ Cypress.Commands.add('getGameByLobbyId', (lobbyId: string) => {
});
});
Cypress.Commands.add('getCurrentTurn', (lobbyId: string, userId: string) => {
Cypress.Commands.add('getCurrentTurn', (gameId: string, username: string) => {
cy.request({
method: 'GET',
url: `${Cypress.config('baseUrl')}/game/${lobbyId}`,
url: `${Cypress.config('baseUrl')}/game/${gameId}/currentTurn`,
body: {
userName: userId,
username: username,
},
}).then((response) => {
expect(response.status).to.eq(200);
......
......@@ -5,9 +5,9 @@ declare namespace Cypress {
deleteUser(username: string): void;
createUser(username: string): void;
getGameByLobbyId(lobbyId: string): void;
getCurrentTurn(lobbyId: string, userId: string): void;
getCurrentTurn(lobbyId: string, username: string): void;
sendMove(gameId: string, gameState: JSON): void;
joinLobby(lobbyId: number, userId: string): void;
joinLobby(lobbyId: number, username: string): void;
getUser(username: string): void;
genericRequest(
method: string,
......
This diff is collapsed.
......@@ -26,7 +26,7 @@
"typescript": "^5.0.4"
},
"dependencies": {
"firebase-admin": "^11.5.0",
"firebase-admin": "^11.6.0",
"node-cache": "^5.1.2",
"prettier": "^2.8.4",
"simplex-noise": "^4.0.1",
......
......@@ -5,6 +5,7 @@ import { getUserById } from '../functions/getUserById';
import { User } from '../../types/User';
import admin from '../functions/firebaseAdmin';
import { IGame } from '../interfaces/IGame';
import { validateGameStateJSON } from '../functions/validateGameStateJSON';
const gameHandler = GameHandler.getInstance();
......@@ -27,9 +28,11 @@ export const move = async (req: Request, res: Response): Promise<void> => {
// return;
// }
game.calculateNextGameState(req.body as IGame);
res.status(200).send('Move made');
if (game.calculateNextGameState(req.body as IGame)) {
res.status(200).send('Move made');
} else {
res.status(400).send('Invalid move');
}
} else {
res.status(404).send('Game not found');
}
......
......@@ -9,7 +9,7 @@ const gameHandler = GameHandler.getInstance();
export const leaveLobby = async (req: Request, res: Response): Promise<void> => {
const id = parseInt(req.params.id);
const lobby = gameHandler.getLobbyById(id);
const user = (await getUserById(req.body.userId)) as User;
const user = (await getUserById(req.body.username)) as User;
lobby?.removeUser(user);
// if lobby is empty, dispose
if (lobby?.getUsers().length === 0) {
......@@ -23,7 +23,7 @@ export const leaveLobby = async (req: Request, res: Response): Promise<void> =>
export const joinLobby = async (req: Request, res: Response): Promise<void> => {
// join a lobby with specific id
const id = parseInt(req.params.id);
const user = (await getUserById(req.body.userId)) as User;
const user = (await getUserById(req.body.username)) as User;
if (gameHandler.getLobbyById(id)) {
const lobby = gameHandler.getLobbyById(id);
......
......@@ -3,25 +3,24 @@ import { GameHandler } from '../gameHandler';
import { getUserById } from '../functions/getUserById';
import { User } from '../../types/User';
import admin from '../functions/firebaseAdmin';
import { getUsers } from '../functions/firebaseCache';
import { getUsers, getUsersIds } from '../functions/firebaseCache';
import { log } from '../functions/console';
const gameHandler = GameHandler.getInstance();
export const users = async (req: Request, res: Response): Promise<void> => {
const users = await getUsers();
const userIds = await getUsersIds();
if (users == null) {
if (userIds == null) {
res.status(204).send('No users found');
} else {
const userids = users.docs.map((doc: { id: any }) => doc.id);
res.status(200).send(userids);
res.status(200).send(userIds);
}
};
// returns data of a specific user
export const getUser = async (req: Request, res: Response): Promise<void> => {
const user = await getUserById(req.params.idOrUsername);
const user = await getUserById(req.params.username);
if (user) {
res.status(200).send(user);
......@@ -34,7 +33,12 @@ export const getUser = async (req: Request, res: Response): Promise<void> => {
export const createUser = async (req: Request, res: Response): Promise<void> => {
const usersRef = admin.firestore().collection('users');
const username = req.params.username;
log('firestore: quering for user with username: ' + username);
if (username === undefined || username === '') {
res.status(400).send('No username provided');
}
log(
'firebase: sending request to firestore quering for user with username: ' + username
);
const user = await getUserById(username);
if (user) {
......@@ -47,7 +51,10 @@ export const createUser = async (req: Request, res: Response): Promise<void> =>
wins: 0,
losses: 0,
};
log('firestore: creating new user with username: ' + username);
log(
'firestore: sending request to firestore creating new user with username: ' +
username
);
const newUserRef = await usersRef.add(initialUserData);
res.status(201).send({ id: newUserRef.id, ...initialUserData } as User);
}
......@@ -57,14 +64,19 @@ export const createUser = async (req: Request, res: Response): Promise<void> =>
export const deleteUser = async (req: Request, res: Response): Promise<void> => {
const usersRef = admin.firestore().collection('users');
const username = req.params.username;
log('firestore: quering for user with username: ' + username);
const querySnapshot = await usersRef.where('username', '==', username).get();
if (!querySnapshot.empty) {
if (username === undefined || username === '') {
res.status(400).send('No username provided');
}
const user = await getUserById(username);
if (user) {
// delete user
const userDoc = querySnapshot.docs[0];
const user: User = { id: userDoc.id, ...userDoc.data() };
log(
'firestore: deleting user with id: ' + user.id + ' and username: ' + user.username
'firestore: sending request to firestore deleting user with id: ' +
user.id +
' and username: ' +
user.username
);
await usersRef.doc(user.id).delete();
res.status(204).send('User deleted');
......
import path from 'path';
// establish connection to firebase
const admin = require('firebase-admin');
// const admin = require('firebase-admin');
import * as admin from 'firebase-admin';
const serviceAccount = path.join(__dirname, '../../..', 'keys', 'fb-key.json');
admin.initializeApp({
......
import NodeCache from 'node-cache';
// import admin from './firebaseAdmin';
import admin from './firebaseAdmin';
import { log } from './console';
import {
CollectionReference,
DocumentReference,
DocumentSnapshot,
Query,
QueryDocumentSnapshot,
QuerySnapshot,
} from 'firebase-admin/firestore';
import { User } from '../../types/User';
/**
* This is a cache and firebaseHandler for the firestore database
* All functions that retrieve data from firestore should be implemented here
*/
// cache for all queries
const queryCache = new NodeCache({ stdTTL: 60 }); // 60 seconds TTL
/**
* This function returns user-id and user-data.
*
* @returns a list of users
*/
export async function getUsers(): Promise<any> {
const usersRef = admin.firestore().collection('users');
const cacheKey = 'userRef';
return retrieveFromCache(usersRef, queryCache, cacheKey);
const cacheKey = 'users';
const responseMapper = (firestoreResponse: QueryDocumentSnapshot[]) => {
return firestoreResponse.map((doc) => {
return { id: doc.id, ...doc.data };
});
};
return retrieveFromCache(usersRef, queryCache, cacheKey, responseMapper);
}
export async function getTopUsers(): Promise<any> {
/**
* This function returns user-id of all users.
*
* @returns a list of user ids
*/
export async function getUsersIds(): Promise<any> {
const usersRef = admin.firestore().collection('users');
const querySnapshot = await usersRef.orderBy('highscore', 'desc').limit(10);
const test = 'test';
const cacheKey = 'userIds';
const responseMapper = (firestoreResponse: QueryDocumentSnapshot[]) => {
return firestoreResponse.map((doc) => {
return doc.id;
});
};
return retrieveFromCache(usersRef, queryCache, cacheKey, responseMapper);
}
/**
* This function returns the top 10 users (highscore).
*
* @returns a list of users
*/
export async function getTopUsers(): Promise<any> {
const usersRef: CollectionReference = admin.firestore().collection('users');
const querySnapshot: Query = usersRef.orderBy('highscore', 'desc').limit(10);
const cacheKey = 'topUsers';
return retrieveFromCache(querySnapshot, queryCache, cacheKey);
const responseMapper = (firestoreResponse: QueryDocumentSnapshot[]) => {
return firestoreResponse.map((doc) => {
return {
id: doc.id,
username: doc.data().username,
highscore: doc.data().highscore,
};
});
};
return retrieveFromCache(querySnapshot, queryCache, cacheKey, responseMapper);
}
/**
......@@ -27,12 +80,15 @@ export async function getTopUsers(): Promise<any> {
* @param ref Firestore reference
* @param cache The cache to retrieve data from
* @param cacheKey The key to use for the cache
* @param responseMapper A function that maps the firestore response to the desired format
*
* @returns cached or firestore result (null if error)
*/
async function retrieveFromCache(
ref: any,
async function retrieveFromCache<T>(
ref: CollectionReference<T> | Query<T> | DocumentReference<T>,
cache: NodeCache,
cacheKey: string
cacheKey: string,
responseMapper?: Function
): Promise<any | null> {
const cachedValue = cache.get(cacheKey);
......@@ -41,29 +97,59 @@ async function retrieveFromCache(
return cachedValue;
} else {
log('Cache-miss: retrieving from firestore...');
return await sendFirestoreRequest(ref, cache, cacheKey);
const firestoreResponse = await sendFirestoreRequest<T>(ref);
if (!firestoreResponse) return null;
const response = responseMapper
? responseMapper(firestoreResponse)
: firestoreResponse;
cache.set(cacheKey, response);
log("Cache-set: set cache for key '" + cacheKey + "'");
return response;
}
}
/**
* Sends a request to firestore and returns the result
*
* @param ref
* @param cache
* @param cacheKey
* @param ref a firestore collection reference
* @returns firestore result
*/
async function sendFirestoreRequest(
ref: any,
cache: NodeCache,
cacheKey: string
): Promise<any | null> {
export async function sendFirestoreRequest<T>(
ref: CollectionReference<T> | Query<T> | DocumentReference<T>
): Promise<Array<{ id: string; data: T }> | { id: string; data: T | null } | null> {
try {
log('firebase: sending request to firestore...');
const snapshot = await ref.get();
cache.set(cacheKey, snapshot);
log("Cache-set: set cache for key '" + cacheKey + "'");
return snapshot;
let data = null;
if (ref instanceof CollectionReference || ref instanceof Query) {
const snapshot = (await (
ref as CollectionReference<T> | Query<T>
).get()) as QuerySnapshot<T>;
if (snapshot.empty) {
// log('No matching documents.');
return null;
}
data = snapshot.docs.map((doc) => {
return { id: doc.id, data: doc.data() };
});
} else if (ref instanceof DocumentReference) {
const snapshot = (await (ref as DocumentReference<T>).get()) as DocumentSnapshot<T>;
// log('document snapshot: ' + JSON.stringify(snapshot));
if (snapshot.exists) {
data = { id: snapshot.id, data: snapshot.data() || null };
} else {
data = { id: snapshot.id, data: null };
}
} else {
throw new Error('Unsupported reference type');
}
return data;
} catch (err: any) {
if (err?.code === 8) {
log('error: firestore max-limit reached', 'danger');
......
// import { QueryDocumentSnapshot } from 'firebase-admin/firestore';
import { DocumentData } from 'firebase-admin/firestore';
import { User } from '../../types/User';
import { log } from './console';
import admin from './firebaseAdmin';
import { getUsers, sendFirestoreRequest } from './firebaseCache';
export async function getUserById(id: string): Promise<User | null> {
const useCache = true; // set to false if you want to query firebase for each request
const usersRef = admin.firestore().collection('users');
const searchParam = id;
let userSnapshot; // result from firebase search
let user: User; // result from cache
// Search for user by id
log('firebase: searching for user by id: ' + searchParam);
let userSnapshot = await usersRef.doc(searchParam).get();
// If the user is not found by id, search for user by username
if (!userSnapshot.exists) {
log('firebase: searching for user by username: ' + searchParam);
const userByUsernameSnapshot = await usersRef
.where('username', '==', searchParam)
.get();
if (!userByUsernameSnapshot.empty) {
userSnapshot = userByUsernameSnapshot.docs[0];
if (searchParam === undefined || searchParam === '') {
log('no id provided');
return null;
}
// If the cache is enabled, try to get the user from the cache
if (useCache) {
const cachedUsers = await getUsers();
if (cachedUsers) {
user = cachedUsers.find(
(u: User) => u.username === searchParam || u.id === searchParam
);
if (user) {
log('User found in cache: ' + user.id);
return user;
}
}
log("User wasn't found in cache");
}
if (userSnapshot) {
log('found user: ' + userSnapshot.id);
return userSnapshot.data() as User;
// no hit in cache, search firebase
let ref = usersRef.where('username', '==', searchParam);
// const userByUsernameSnapshot = await usersRef.where('username', '==', searchParam).get();
// Map the response to a more readable format
// const responseMapper = (firestoreResponse: QueryDocumentSnapshot[]) => {
// return firestoreResponse.map((doc) => {
// return { id: doc.id, ...doc.data() };
// });
// };
let result = await sendFirestoreRequest(ref);
if (result) {
// return result;
const myData = (result as { id: string; data: DocumentData }[])[0];
// map the contents of myData into a User object
const user: User = {
id: myData.id,
username: myData.data.username,
wins: myData.data.wins,
losses: myData.data.losses,
highscore: myData.data.highscore,
games: myData.data.games,
};
log('User found by username: ' + myData.data.username);
return user;
} else {
log('User not found');
return null;
let usernameRef = usersRef.doc(searchParam);
result = null;
result = await sendFirestoreRequest(usernameRef);
if (result) {
const myData = result as { id: string; data: DocumentData };
if (myData.data != null) {
// map the contents of myData into a User object
const user: User = {
id: myData.id,
username: myData.data.username,
wins: myData.data.wins,
losses: myData.data.losses,
highscore: myData.data.highscore,
games: myData.data.games,
};
log('User found by id: ' + user.id);
return user;
}
}
}
log('User not found: ' + searchParam);
return null;
}
......@@ -22,7 +22,7 @@ export interface IGame {
getLoser(): User;
setScore(user: number, score: number): void;
getScore(user: number): number;
calculateNextGameState(newGameState: IGame): void;
calculateNextGameState(newGameState: IGame): boolean;
getGameState(): IGame;
setGameState(gameState: IGame): void;
......
......@@ -112,23 +112,23 @@ export class Game implements IGame {
}
}
calculateNextGameState(newGameState: IGame): void {
calculateNextGameState(newGameState: IGame): boolean {
// verify that json is a valid IGame object
// compare the current game state with the new game state
if (newGameState.gameId !== this.gameId) {
log('Game ID mismatch');
return;
return false;
}
if (newGameState.gameStatus !== this.gameStatus) {
log('Game status mismatch');
return;
return false;
}
if (newGameState.users.length !== this.users.length) {
log('User length mismatch');
return;
return false;
}
// check if a projectile was fired (we assume that the projectile is always fired by the current user)
......@@ -172,6 +172,7 @@ export class Game implements IGame {
this.toggleTurn();
}
log('Game state updated for game ' + this.gameId);
return true;
}
// update the game state (does not update the current turn)
......
......@@ -25,7 +25,7 @@ router.get('/:lobbyId', gameController.gameId);
/**
* @swagger
* /game/move:
* /game/{gameId}/move:
* post:
* tags: [Game]
* summary: Send a move.
......
{
"compilerOptions": {
"target": "es5",
"target": "es6",
"module": "commonjs",
"esModuleInterop": true,
"outDir": "dist",
......
......@@ -1523,10 +1523,10 @@ finalhandler@1.2.0:
statuses "2.0.1"
unpipe "~1.0.0"
firebase-admin@^11.5.0:
version "11.5.0"
resolved "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.5.0.tgz"
integrity sha512-bBdlYtNvXx8yZGdCd00NrfZl1o1A0aXOw5h8q5PwC8RXikOLNXq8vYtSKW44dj8zIaafVP6jFdcUXZem/LMsHA==
firebase-admin@^11.6.0:
version "11.6.0"
resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-11.6.0.tgz#1ab3b80648c6c90aba8283185a6489187e975c25"
integrity sha512-Kvjs+u/EHs+8B4pNOehbXkazEVMNmTQjkz+B5vUIvWWWR44GOiZj4lBf/hM5An4k3rFkBfO6G4s0kWi7QMOm3g==
dependencies:
"@fastify/busboy" "^1.1.0"
"@firebase/database-compat" "^0.3.0"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment