Browse Source

refactor: backend to TS

mongoose
ntasicc 3 years ago
parent
commit
4aca4a6763

+ 92
- 0
models/order.ts View File

@@ -0,0 +1,92 @@
const validator = require('validator');
import { ProductData as IProduct } from '../utils/interface/productInterface';
import { OrderData as IOrder } from '../utils/interface/orderInterface';
import { Schema, model, Types } from 'mongoose';

const OrderSchema = new Schema<IOrder>(
{
products: Array<IProduct>,
time: {
type: Date,
required: [true, 'Please provide a date.'],
validate(value: Date) {
if (!validator.isDate(value)) {
throw new Error('Not a date');
}
},
},
shippingAddress: {
country: {
type: String,
required: [true, 'Please provide a country.'],
trim: true,
},
city: {
type: String,
required: [true, 'Please provide a city.'],
trim: true,
},
address: {
type: String,
required: [true, 'Please provide an address.'],
trim: true,
},
address2: {
type: String,
trim: true,
},
postcode: {
type: String,
required: [true, 'Please provide a postal code.'],
},
email: {
type: String,
required: [true, 'Please provide an email.'],
},
fullName: {
type: String,
required: [true, 'Please provide a name.'],
},
},

totalPrice: {
type: Number,
required: [true, 'Please provide a total price.'],
validate(value: number) {
if (value < 0) {
throw new Error('Total price must be a postive number');
}
},
},
numberOfItems: {
type: Number,
required: [true, 'Please provide a total number of items.'],
validate(value: number) {
if (value < 0) {
throw new Error('Number of items must be a postive number');
}
},
},
fulfilled: {
type: Boolean,
default: false,
},
owner: {
type: Types.ObjectId,
required: [true, 'Please provide an owner.'],
ref: 'User',
},
stripeCheckoutId: {
type: String,
required: [true, 'Please provide a stripe checkout id.'],
},
},
{
toJSON: { virtuals: true }, // So `res.json()` and other `JSON.stringify()` functions include virtuals
toObject: { virtuals: true }, // So `console.log()` and other functions that use `toObject()` include virtuals
}
);

const Order = model<IOrder>('Order', OrderSchema, 'Order');

module.exports = Order;

+ 73
- 0
models/product.ts View File

@@ -0,0 +1,73 @@
import { ProductData as IProduct } from '../utils/interface/productInterface';
import { Schema, model } from 'mongoose';

const ProductSchema = new Schema<IProduct>({
category: {
type: String,
required: [true, 'Please provide a category.'],
maxlength: 100,
trim: true,
},
name: {
type: String,
required: [true, 'Please provide a name.'],
maxlength: 100,
trim: true,
},
image: {
type: String,
required: [true, 'Please provide an image.'],
},
description: {
type: String,
required: [true, 'Please provide a description.'],
trim: true,
},
place: {
type: String,
trim: true,
},
people: {
type: String,
trim: true,
},
process: {
type: String,
trim: true,
},
pairing: {
type: String,
trim: true,
},
available: {
type: Boolean,
default: true,
},
isFeatured: {
type: Boolean,
default: false,
},
price: {
type: Number,
required: [true, 'Please provide a price.'],
validate(value: number) {
if (value < 0) {
throw new Error('Price must be a postive number');
}
},
},
customID: {
type: String,
required: [true, 'Please provide a custom id.'],
unique: true,
},
stripeID: {
type: String,
required: [true, 'Please provide a stripe id.'],
unique: true,
},
});

const Product = model<IProduct>('Product', ProductSchema);

module.exports = Product;

+ 39
- 0
models/question.ts View File

@@ -0,0 +1,39 @@
import { Schema, model } from 'mongoose';
import { QuestionData as IQusetion } from '../utils/interface/questionInterface';

const validator = require('validator');

const QuestionSchema = new Schema<IQusetion>({
firstName: {
type: String,
required: [true, 'Please provide a name.'],
maxlength: [60, 'Name cannot be more than 60 characters'],
trim: true,
},
lastName: {
type: String,
required: [true, 'Please provide a last name.'],
maxlength: [60, 'Name cannot be more than 60 characters'],
trim: true,
},
email: {
type: String,
required: [true, 'Please provide an email.'],
trim: true,
lowercase: true,
unique: false,
validate(value: string) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid');
}
},
},
message: {
type: String,
required: [true, 'Please provide a message/question.'],
trim: true,
},
});

const Question = model<IQusetion>('Question', QuestionSchema, 'Questions');
module.exports = Question;

+ 128
- 0
models/user.ts View File

@@ -0,0 +1,128 @@
import { Schema, model, Model } from 'mongoose';
import {
hashPassword,
verifyPassword,
} from '../utils/helpers/hashPasswordHelpers';
import { IUser } from '../utils/interface/userInterface';
const validator = require('validator');

interface UserModel extends Model<IUser, {}, {}> {
findByCredentials(username: string, password: string): object;
}

const UserSchema = new Schema<IUser, UserModel>(
{
fullName: {
type: String,
required: [true, 'Please provide a name.'],
maxlength: [60, 'Name cannot be more than 60 characters'],
trim: true,
},
username: {
type: String,
required: [true, 'Please provide an username.'],
unique: true,
maxlength: [60, 'Name cannot be more than 60 characters'],
trim: true,
},
email: {
type: String,
unique: true,
required: [true, 'Please provide an email.'],
trim: true,
lowercase: true,
validate(value: string) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid');
}
},
},
password: {
type: String,
required: [true, 'Please provide a password.'],
minlength: 7,
trim: true,
validate(value: string) {
if (value.toLowerCase().includes('password')) {
throw new Error('Password cannot contain "password"');
}
},
},
country: {
type: String,
required: [true, 'Please provide a country.'],
trim: true,
},
city: {
type: String,
required: [true, 'Please provide a city.'],
trim: true,
},
address: {
type: String,
required: [true, 'Please provide an address.'],
trim: true,
},
address2: {
type: String,
trim: true,
},
postcode: {
type: String,
required: [true, 'Please provide a postal code.'],
},
},
{
toJSON: { virtuals: true }, // So `res.json()` and other `JSON.stringify()` functions include virtuals
toObject: { virtuals: true }, // So `console.log()` and other functions that use `toObject()` include virtuals
}
);

UserSchema.virtual('orders', {
ref: 'Order',
localField: '_id',
foreignField: 'owner',
});

UserSchema.static(
'findByCredentials',
async function findByCredentials(username: string, password: string) {
const user = await User.findOne({ username });

if (!user) {
throw new Error('Unable to login');
}

const isMatch = await verifyPassword(password, user.password);

if (!isMatch) {
throw new Error('Unable to login');
}

const userData = {
fullName: user.fullName,
email: user.email,
address: user.address,
address2: user.address2,
city: user.city,
country: user.country,
postcode: user.postcode,
orders: user.orders,
_id: user._id,
};
return userData;
}
);

UserSchema.pre('save', async function (next) {
const user = this;

if (user.isModified('password')) {
user.password = await hashPassword(user.password);
}

next();
});

const User = model<IUser, UserModel>('User', UserSchema, 'User');
module.exports = User;

+ 8
- 1
package.json View File

@@ -9,10 +9,17 @@
"lint": "next lint"
},
"dependencies": {
"@sendgrid/mail": "^7.7.0",
"@types/bcryptjs": "^2.4.2",
"@types/mongodb": "^4.0.7",
"@types/validator": "^13.7.7",
"bcryptjs": "^2.4.3",
"mongoose": "^6.6.5",
"next": "12.3.1",
"next-auth": "^4.13.0",
"react": "18.2.0",
"react-dom": "18.2.0"
"react-dom": "18.2.0",
"validator": "^13.7.0"
},
"devDependencies": {
"@types/node": "18.8.3",

+ 40
- 0
pages/api/auth/[...nextauth].ts View File

@@ -0,0 +1,40 @@
import NextAuth from 'next-auth';
import Credentials from 'next-auth/providers/credentials';
import dbConnect from '../../../utils/helpers/dbHelpers';
const User = require('../../../models/user');

export default NextAuth({
session: {
strategy: 'jwt',
},
callbacks: {
async jwt({ token, user, account, profile, isNewUser }) {
return { ...token, ...user };
},
async session({ session, token, user }) {
return session;
},
},
providers: [
Credentials({
name: 'Credentials',
credentials: {
username: { label: 'Username', type: 'text' },
password: { label: 'Password', type: 'password' },
},
// @ts-ignore
async authorize(credentials) {
if (credentials) {
await dbConnect();

const userData = await User.findByCredentials(
credentials.username,
credentials.password
);
return { user: userData };
}
return null;
},
}),
],
});

+ 34
- 0
pages/api/auth/signup.ts View File

@@ -0,0 +1,34 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import dbConnect from '../../../utils/helpers/dbHelpers';
import { UpdateResponse, IUser } from '../../../utils/interface/userInterface';
const User = require('../../../models/user');

async function handler(
req: NextApiRequest,
res: NextApiResponse<UpdateResponse>
) {
const { method } = req;

await dbConnect();

switch (method) {
case 'POST': {
try {
const user: IUser = await User.create(req.body);
res
.status(201)
.json({ message: `User (${user.fullName}) created sucessfully!` });
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
}
}

export default handler;

+ 0
- 13
pages/api/hello.ts View File

@@ -1,13 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
name: string
}

export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

+ 66
- 0
pages/api/order/index.ts View File

@@ -0,0 +1,66 @@
const Order = require('../../../models/order');
import dbConnect from '../../../utils/helpers/dbHelpers';
import { Types } from 'mongoose';
import type { NextApiRequest, NextApiResponse } from 'next';
import {
OrderResponse,
OrderDataDB,
} from '../../../utils/interface/orderInterface';

async function handler(
req: NextApiRequest,
res: NextApiResponse<OrderResponse>
) {
const { method } = req;
const ownerID = req.query.ownerID as string;
await dbConnect();

switch (method) {
case 'POST': {
try {
const order: OrderDataDB = await Order.create(
req.body
); /* create a new model in the database */
res
.status(201)
.json({ message: 'Your order was submitted successfully!', order });
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
case 'GET': {
try {
const objectId = new Types.ObjectId(ownerID);
const orders: Array<OrderDataDB> = await Order.find({
owner: objectId,
});
if (!orders) {
res.status(200).json({
message:
'There are currently no orders in our database for the selected owner.',
orders: [],
});
}

res.status(200).json({
message:
'All orders from our database for the selected owner were fetched successfully.',
orders,
});
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
}
}

export default handler;

+ 57
- 0
pages/api/product/[productId].ts View File

@@ -0,0 +1,57 @@
const Product = require('../../../models/product');
import dbConnect from '../../../utils/helpers/dbHelpers';
import type { NextApiRequest, NextApiResponse } from 'next';
import {
ProductDataDB,
SingleProductResponse,
} from '../../../utils/interface/productInterface';

async function handler(
req: NextApiRequest,
res: NextApiResponse<SingleProductResponse>
) {
const { method } = req;

await dbConnect();

switch (method) {
case 'GET': {
try {
const productId = req.query.productId;

const product: ProductDataDB = await Product.findOne({
customID: productId,
});

if (!product) {
throw new Error('The product with this id does not exist!');
}

const similarProducts: Array<ProductDataDB> = await Product.find({
category: product.category,
customID: { $ne: product.customID },
});

const shuffled = similarProducts
.sort(() => 0.5 - Math.random())
.slice(0, 3);

res.status(200).json({
message: 'The product you requested was fetched successfully.',
product,
similarProducts: shuffled,
});
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
}
}

export default handler;

+ 48
- 0
pages/api/product/featured-products.ts View File

@@ -0,0 +1,48 @@
const Product = require('../../../models/product');
import dbConnect from '../../../utils/helpers/dbHelpers';
import type { NextApiRequest, NextApiResponse } from 'next';
import {
ProductDataDB,
FeaturedProductsResponse,
} from '../../../utils/interface/productInterface';

async function handler(
req: NextApiRequest,
res: NextApiResponse<FeaturedProductsResponse>
) {
const { method } = req;

await dbConnect();

switch (method) {
case 'GET': {
try {
const featuredProducts: Array<ProductDataDB> = await Product.find({
isFeatured: true,
});

if (!featuredProducts) {
res.status(200).json({
message: 'There are no featured products right now.',
featuredProducts: [],
});
}

res.status(200).json({
message: 'Featured products were fetched successfully.',
featuredProducts,
});
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
}
}

export default handler;

+ 103
- 0
pages/api/product/index.ts View File

@@ -0,0 +1,103 @@
const Product = require('../../../models/product');
import dbConnect from '../../../utils/helpers/dbHelpers';
import type { NextApiRequest, NextApiResponse } from 'next';
import {
ProductDataDB,
ProductsResponse,
} from '../../../utils/interface/productInterface';

async function handler(
req: NextApiRequest,
res: NextApiResponse<ProductsResponse>
) {
const { method } = req;

await dbConnect();

const pageIndex = parseInt(req.query.pageIndex as string);
const category = req.query.category === 'All' ? '' : req.query.category;
const filterType = req.query.filterType;

if (pageIndex < 1) {
res.status(422).json({
message: 'Page does not exist ',
});
return;
}

switch (method) {
case 'GET': {
try {
const productCount: number = await Product.find({
category: { $regex: category },
}).countDocuments();

if (productCount === 0) {
res.status(200).json({
message: 'There are currently no products in our database.',
product: [],
productCount: 0,
next: '',
previous: '',
});
break;
}

if ((pageIndex - 1) * 9 >= productCount) {
throw new Error('Page does not exist!');
}

const product: Array<ProductDataDB> = await Product.find({
category: { $regex: category },
})
.skip((pageIndex - 1) * 9)
.limit(9)
.sort(filterType === 'asc' ? 'name' : '-name ');

if (!product) {
throw new Error('There are currently no products in our database.');
}

const previousUrl =
pageIndex > 1
? `https://localhost:3000/api/product?pageIndex=${pageIndex - 1}`
: '';
const nextUrl =
pageIndex * 9 < productCount
? `https://localhost:3000/api/product?pageIndex=${pageIndex + 1}`
: '';

res.status(200).json({
message: 'All products from our database were fetched successfully.',
product,
productCount,
next: nextUrl,
previous: previousUrl,
});
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
case 'POST': {
try {
const product: ProductDataDB = await Product.create(req.body);
res
.status(201)
.json({ message: 'Your product was created and stored!', product });
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
}
}

export default handler;

+ 54
- 0
pages/api/question/index.ts View File

@@ -0,0 +1,54 @@
const Question = require('../../../models/question');
import dbConnect from '../../../utils/helpers/dbHelpers';
const sgMail = require('@sendgrid/mail');
import type { NextApiRequest, NextApiResponse } from 'next';
import {
QuestionDataDB,
QuestionResponse,
} from '../../../utils/interface/questionInterface';

async function handler(
req: NextApiRequest,
res: NextApiResponse<QuestionResponse>
) {
const { method } = req;
await dbConnect();

switch (method) {
case 'POST': {
try {
const question: QuestionDataDB = await Question.create(req.body);

sgMail.setApiKey(process.env.NEXT_PUBLIC_SEND_GRID);

const msg = {
to: '[email protected]', //req.body.email, // Change to your recipient
from: '[email protected]', // Change to your verified sender
subject: 'Question submitted',
text: 'Your question was submitted successfully, we will contact you via email shortly. Thank you!',
html: '<strong>Your question was submitted successfully, we will contact you via email shortly. Thank you!</strong>',
};

sgMail.send(msg).then(() => {
console.log('Email sent');
});

res.status(201).json({
message:
'Your message/question was submitted successfully, check your mail for confirmation.',
question,
});
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
}
}

export default handler;

+ 51
- 0
pages/api/user/index.ts View File

@@ -0,0 +1,51 @@
const User = require('../../../models/user');
import dbConnect from '../../../utils/helpers/dbHelpers';
import type { NextApiRequest, NextApiResponse } from 'next';
import { UpdateResponse } from '../../../utils/interface/userInterface';

async function handler(
req: NextApiRequest,
res: NextApiResponse<UpdateResponse>
) {
const { method } = req;

await dbConnect();

switch (method) {
case 'PATCH': {
const updates = Object.keys(req.body.userData);
const allowedUpdates = [
'fullName',
'email',
'address',
'address2',
'city',
'country',
'postcode',
];
const isValidOperation = updates.every((update) =>
allowedUpdates.includes(update)
);

if (!isValidOperation) {
return res.status(400).send({ message: 'Invalid updates!' });
}

try {
const user = await User.findOne({ _id: req.body._id });
updates.forEach((update) => (user[update] = req.body.userData[update]));
await user.save();
res.send({
message: 'User profile updated successfully.',
});
} catch (error) {
if (error instanceof Error)
res.status(400).json({ message: error.message });
else res.status(400).json({ message: 'Unexpected error' + error });
}
break;
}
}
}

export default handler;

+ 5
- 14
requests/orders/getOrdersForOwnerRequest.ts View File

@@ -1,23 +1,14 @@
import apiEndpoints from '../apiEndpoints';
import { OrderData } from '../../utils/interface/orderInterface';
import { OrderResponseGet } from '../../utils/interface/orderInterface';

interface OrderDataDB extends OrderData {
id: string;
_id: string;
__v: number;
}

interface OrderResponse {
message: string;
orders: Array<OrderDataDB>;
}

export const getOrdersForOwner = async (id: string): Promise<OrderResponse> => {
export const getOrdersForOwner = async (
id: string
): Promise<OrderResponseGet> => {
const response = await fetch(
`http://localhost:3000${apiEndpoints.order}?ownerID=${id}`
);

const data: OrderResponse = await response.json();
const data: OrderResponseGet = await response.json();

if (!response.ok) {
throw new Error(data.message || 'Something went wrong!');

+ 6
- 13
requests/orders/postOrderRequest.ts View File

@@ -1,19 +1,12 @@
import apiEndpoints from '../apiEndpoints';
import { OrderData } from '../../utils/interface/orderInterface';
import {
OrderResponsePost,
OrderData,
} from '../../utils/interface/orderInterface';

interface OrderDataDB extends OrderData {
id: string;
_id: string;
__v: number;
}

interface OrderResponse {
message: string;
order: OrderDataDB;
}
export const postOrder = async (
orderData: OrderData
): Promise<OrderResponse> => {
): Promise<OrderResponsePost> => {
const response = await fetch(`http://localhost:3000${apiEndpoints.order}`, {
method: 'POST',
body: JSON.stringify(orderData),
@@ -22,7 +15,7 @@ export const postOrder = async (
},
});

const data: OrderResponse = await response.json();
const data: OrderResponsePost = await response.json();

if (!response.ok) {
throw new Error(data.message || 'Something went wrong!');

+ 1
- 12
requests/products/featuredProductsRequest.ts View File

@@ -1,17 +1,6 @@
import { ProductData } from '../../utils/interface/productInterface';
import { FeaturedProductsResponse } from '../../utils/interface/productInterface';
import apiEndpoints from '../apiEndpoints';

interface ProductDataDB extends ProductData {
id: string;
_id: string;
__v: number;
}

interface FeaturedProductsResponse {
message: string;
featuredProducts: Array<ProductDataDB>;
}

export const getFeaturedProducts =
async (): Promise<FeaturedProductsResponse> => {
const response = await fetch(

+ 1
- 6
requests/products/producDataRequest.ts View File

@@ -1,11 +1,6 @@
import { SingleProductResponse } from '../../utils/interface/productInterface';
import apiEndpoints from '../apiEndpoints';

interface SingleProductResponse {
message: string;
product: object;
similarProducts: Array<object>;
}

export const getProductData = async (
productId: string
): Promise<SingleProductResponse> => {

+ 1
- 8
requests/products/productRequest.ts View File

@@ -1,13 +1,6 @@
import { ProductsResponse } from '../../utils/interface/productInterface';
import apiEndpoints from '../apiEndpoints';

interface ProductsResponse {
message: string;
product: object;
productCount: number;
next: string;
previous: string;
}

export const getAllProducts = async (
pageIndex: number,
category = 'All',

+ 4
- 6
requests/question/postQuestionRequest.ts View File

@@ -1,10 +1,8 @@
import apiEndpoints from '../apiEndpoints';
import { QuestionData } from '../../utils/interface/questionInterface';

interface QuestionResponse {
message: string;
question: { [key: string]: string };
}
import {
QuestionData,
QuestionResponse,
} from '../../utils/interface/questionInterface';

export const postQuestion = async (
questionData: QuestionData

+ 1
- 5
requests/user/userUpdateRequest.ts View File

@@ -1,9 +1,5 @@
import apiEndpoints from '../apiEndpoints';
import { UserData } from '../../utils/interface/userInterface';

interface UpdateResponse {
message: string;
}
import { UserData, UpdateResponse } from '../../utils/interface/userInterface';

export const updateUser = async (
userData: UserData,

+ 51
- 0
utils/helpers/dbHelpers.ts View File

@@ -0,0 +1,51 @@
import { MongoClient } from 'mongodb';
import mongoose from 'mongoose';

export async function connectToDatabase() {
const client = await MongoClient.connect(process.env.MONGODB_URI!);

return client;
}

declare global {
var mongoose: any;
}

const MONGODB_URI = process.env.MONGODB_URI;

if (!MONGODB_URI) {
throw new Error(
'Please define the MONGODB_URI environment variable inside .env.local'
);
}

/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
let cached = global.mongoose;

if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}

async function dbConnect() {
if (cached.conn) {
return cached.conn;
}

if (!cached.promise) {
const opts = {
bufferCommands: false,
};

cached.promise = mongoose.connect(MONGODB_URI!, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}

export default dbConnect;

+ 11
- 0
utils/helpers/hashPasswordHelpers.ts View File

@@ -0,0 +1,11 @@
import { hash, compare } from 'bcryptjs';

export async function hashPassword(password: string) {
const hashedPassword = await hash(password, 12);
return hashedPassword;
}

export async function verifyPassword(password: string, hashedPassword: string) {
const isValid = await compare(password, hashedPassword);
return isValid;
}

+ 25
- 0
utils/interface/orderInterface.ts View File

@@ -16,3 +16,28 @@ export interface OrderData {
owner: ObjectId;
stripeCheckoutId: string;
}

export interface OrderDataDB extends OrderData {
id: string;
_id: string;
__v: number;
}

export interface OrderResponseGet {
message: string;
orders: Array<OrderDataDB>;
}

export interface OrderResponsePost {
message: string;
order: OrderDataDB;
}

export interface OrderResponseError {
message: string;
}

export type OrderResponse =
| OrderResponseGet
| OrderResponsePost
| OrderResponseError;

+ 47
- 0
utils/interface/productInterface.ts View File

@@ -13,3 +13,50 @@ export interface ProductData {
customID: string;
stripeID: string;
}

export interface ProductDataDB extends ProductData {
id: string;
_id: string;
__v: number;
}

export interface FeaturedProductsResponseGet {
message: string;
featuredProducts: Array<ProductDataDB>;
}

export interface ProductsResponseGet {
message: string;
product: Array<ProductData>;
productCount: number;
next: string;
previous: string;
}

export interface ProductsResponseError {
message: string;
}

export interface ProductsResponsePost {
message: string;
product: ProductData;
}

interface SingleProductResponseGet {
message: string;
product: ProductDataDB;
similarProducts: Array<ProductDataDB>;
}

export type SingleProductResponse =
| SingleProductResponseGet
| ProductsResponseError;

export type ProductsResponse =
| ProductsResponseGet
| ProductsResponsePost
| ProductsResponseError;

export type FeaturedProductsResponse =
| FeaturedProductsResponseGet
| ProductsResponseError;

+ 17
- 0
utils/interface/questionInterface.ts View File

@@ -4,3 +4,20 @@ export interface QuestionData {
lastName: string;
message: string;
}

export interface QuestionDataDB extends QuestionData {
id: string;
_id: string;
__v: number;
}

export interface QuestionResponsePost {
message: string;
question: QuestionData;
}

export interface QuestionError {
message: string;
}

export type QuestionResponse = QuestionResponsePost | QuestionError;

+ 11
- 0
utils/interface/userInterface.ts View File

@@ -6,3 +6,14 @@ export interface UserData {
fullName: string;
postcode: string;
}

export interface IUser extends UserData {
email: string;
username: string;
password: string;
orders?: Array<object>;
}

export interface UpdateResponse {
message: string;
}

+ 200
- 9
yarn.lock View File

@@ -17,6 +17,13 @@
dependencies:
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.16.3":
version "7.19.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
dependencies:
regenerator-runtime "^0.13.4"

"@eslint/eslintrc@^1.3.3":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95"
@@ -149,11 +156,39 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"

"@panva/hkdf@^1.0.1":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.0.2.tgz#bab0f09d09de9fd83628220d496627681bc440d6"
integrity sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==

"@rushstack/eslint-patch@^1.1.3":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728"
integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==

"@sendgrid/client@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.7.0.tgz#f8f67abd604205a0d0b1af091b61517ef465fdbf"
integrity sha512-SxH+y8jeAQSnDavrTD0uGDXYIIkFylCo+eDofVmZLQ0f862nnqbC3Vd1ej6b7Le7lboyzQF6F7Fodv02rYspuA==
dependencies:
"@sendgrid/helpers" "^7.7.0"
axios "^0.26.0"

"@sendgrid/helpers@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@sendgrid/helpers/-/helpers-7.7.0.tgz#93fb4b6e2f0dc65080440d6a784cc93e8e148757"
integrity sha512-3AsAxfN3GDBcXoZ/y1mzAAbKzTtUZ5+ZrHOmWQ279AuaFXUNCh9bPnRpN504bgveTqoW+11IzPg3I0WVgDINpw==
dependencies:
deepmerge "^4.2.2"

"@sendgrid/mail@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@sendgrid/mail/-/mail-7.7.0.tgz#aba09f5ce2e9d8ceee92284c3ea8b4a90b0e38fe"
integrity sha512-5+nApPE9wINBvHSUxwOxkkQqM/IAAaBYoP9hw7WwgDNQPxraruVqHizeTitVtKGiqWCKm2mnjh4XGN3fvFLqaw==
dependencies:
"@sendgrid/client" "^7.7.0"
"@sendgrid/helpers" "^7.7.0"

"@swc/[email protected]":
version "0.4.11"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de"
@@ -161,6 +196,11 @@
dependencies:
tslib "^2.4.0"

"@types/bcryptjs@^2.4.2":
version "2.4.2"
resolved "https://registry.yarnpkg.com/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae"
integrity sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==

"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@@ -204,6 +244,11 @@
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==

"@types/validator@^13.7.7":
version "13.7.7"
resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.7.tgz#e87cf34dd08522d21acf30130fd8941f433b81b5"
integrity sha512-jiEw2kTUJ8Jsh4A1K4b5Pkjj9Xz6FktLLOQ36ZVLRkmxFbpTvAV2VRoKMojz8UlZxNg/2dZqzpigH4JYn1bkQg==

"@types/webidl-conversions@*":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7"
@@ -352,6 +397,13 @@ axe-core@^4.4.3:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.3.tgz#11c74d23d5013c0fa5d183796729bc3482bd2f6f"
integrity sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==

axios@^0.26.0:
version "0.26.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
dependencies:
follow-redirects "^1.14.8"

axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@@ -367,6 +419,11 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==

bcryptjs@^2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==

brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -382,7 +439,7 @@ braces@^3.0.2:
dependencies:
fill-range "^7.0.1"

bson@^4.7.0:
bson@^4.6.5, bson@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/bson/-/bson-4.7.0.tgz#7874a60091ffc7a45c5dd2973b5cad7cded9718a"
integrity sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==
@@ -440,6 +497,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==

cookie@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==

core-js-pure@^3.25.1:
version "3.25.5"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.25.5.tgz#79716ba54240c6aa9ceba6eee08cf79471ba184d"
@@ -464,6 +526,13 @@ damerau-levenshtein@^1.0.8:
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==

[email protected], debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"

debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -478,18 +547,16 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"

debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"

deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==

deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==

define-properties@^1.1.3, define-properties@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
@@ -854,6 +921,11 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==

follow-redirects@^1.14.8:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==

fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1148,6 +1220,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==

jose@^4.1.4, jose@^4.9.3:
version "4.10.0"
resolved "https://registry.yarnpkg.com/jose/-/jose-4.10.0.tgz#2e0b7bcc80dd0775f8a4588e55beb9460c37d60a"
integrity sha512-KEhB/eLGLomWGPTb+/RNbYsTjIyx03JmbqAyIyiXBuNSa7CmNrJd5ysFhblayzs/e/vbOPMUaLnjHUMhGp4yLw==

js-sdsl@^4.1.4:
version "4.1.5"
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a"
@@ -1190,6 +1267,11 @@ json5@^1.0.1:
array-includes "^3.1.5"
object.assign "^4.1.3"

[email protected]:
version "2.4.1"
resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.4.1.tgz#7d81ec518204a48c1cb16554af126806c3cd82b0"
integrity sha512-aJ9opVoXroQUPfovYP5kaj2lM7Jn02Gw13bL0lg9v0V7SaUc0qavPs0Eue7d2DcC3NjqI6QAUElXNsuZSeM+EA==

language-subtag-registry@~0.3.2:
version "0.3.22"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
@@ -1286,6 +1368,43 @@ mongodb@*:
optionalDependencies:
saslprep "^1.0.3"

[email protected]:
version "4.9.1"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.9.1.tgz#0c769448228bcf9a6aa7d16daa3625b48312479e"
integrity sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==
dependencies:
bson "^4.7.0"
denque "^2.1.0"
mongodb-connection-string-url "^2.5.3"
socks "^2.7.0"
optionalDependencies:
saslprep "^1.0.3"

mongoose@^6.6.5:
version "6.6.5"
resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.6.5.tgz#fcc7ba9594db711b3d4d7a1b3522c5dbc8f0bf52"
integrity sha512-iA/oDpWOc+K2QYzA4Eq7Z1oUBQOz9FGDmUwPLgw872Bfs/qizA5Db+gJorAn+TnnGu3VoCK8iP4Y+TECUelwjA==
dependencies:
bson "^4.6.5"
kareem "2.4.1"
mongodb "4.9.1"
mpath "0.9.0"
mquery "4.0.3"
ms "2.1.3"
sift "16.0.0"

[email protected]:
version "0.9.0"
resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904"
integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==

[email protected]:
version "4.0.3"
resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.3.tgz#4d15f938e6247d773a942c912d9748bd1965f89d"
integrity sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==
dependencies:
debug "4.x"

[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -1296,7 +1415,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==

ms@^2.1.1:
[email protected], ms@^2.1.1:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -1311,6 +1430,21 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==

next-auth@^4.13.0:
version "4.13.0"
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.13.0.tgz#93d312cec2513ac3c5eb583ee0665da50059a902"
integrity sha512-FtkPpeb9Bax6yKDaxcaGIvZZjvr10JaU2AsBYv1yv4N6rP86Xa7/4Ro1Aq94YGwsYzk+YKS52CRjD2DqCcSmVA==
dependencies:
"@babel/runtime" "^7.16.3"
"@panva/hkdf" "^1.0.1"
cookie "^0.5.0"
jose "^4.9.3"
oauth "^0.9.15"
openid-client "^5.1.0"
preact "^10.6.3"
preact-render-to-string "^5.1.19"
uuid "^8.3.2"

[email protected]:
version "12.3.1"
resolved "https://registry.yarnpkg.com/next/-/next-12.3.1.tgz#127b825ad2207faf869b33393ec8c75fe61e50f1"
@@ -1337,11 +1471,21 @@ [email protected]:
"@next/swc-win32-ia32-msvc" "12.3.1"
"@next/swc-win32-x64-msvc" "12.3.1"

oauth@^0.9.15:
version "0.9.15"
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==

object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==

object-hash@^2.0.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==

object-inspect@^1.12.2, object-inspect@^1.9.0:
version "1.12.2"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
@@ -1397,6 +1541,11 @@ object.values@^1.1.5:
define-properties "^1.1.3"
es-abstract "^1.19.1"

oidc-token-hash@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz#ae6beec3ec20f0fd885e5400d175191d6e2f10c6"
integrity sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==

once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -1404,6 +1553,16 @@ once@^1.3.0:
dependencies:
wrappy "1"

openid-client@^5.1.0:
version "5.1.10"
resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.1.10.tgz#add6044878b9be75ffdd09abfcaae6feff376b1f"
integrity sha512-KYAtkxTuUwTvjAmH0QMFFP3i9l0+XhP2/blct6Q9kn+DUJ/lu8/g/bI8ghSgxz9dJLm/9cpB/1uLVGTcGGY0hw==
dependencies:
jose "^4.1.4"
lru-cache "^6.0.0"
object-hash "^2.0.1"
oidc-token-hash "^5.0.1"

optionator@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
@@ -1481,11 +1640,28 @@ [email protected]:
picocolors "^1.0.0"
source-map-js "^1.0.2"

preact-render-to-string@^5.1.19:
version "5.2.5"
resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.2.5.tgz#359b14a45bea2a7b5c0ed2a9c6eb7ea915cf7d5a"
integrity sha512-rEBn42C3Wh+AjPxXUbDkb6xw0cTJQgxdYlp6ytUR1uBZF647Wn6ykkopMeQlRl7ggX+qnYYjZ4Hs1abZENl7ww==
dependencies:
pretty-format "^3.8.0"

preact@^10.6.3:
version "10.11.1"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.11.1.tgz#35fdad092de8b2ad29df3a0bef9af1f4fdd2256b"
integrity sha512-1Wz5PCRm6Fg+6BTXWJHhX4wRK9MZbZBHuwBqfZlOdVm2NqPe8/rjYpufvYCwJSGb9layyzB2jTTXfpCTynLqFQ==

prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==

pretty-format@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385"
integrity sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==

prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
@@ -1642,6 +1818,11 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"

[email protected]:
version "16.0.0"
resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.0.tgz#447991577db61f1a8fab727a8a98a6db57a23eb8"
integrity sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==

slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -1823,6 +2004,16 @@ [email protected]:
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==

uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==

validator@^13.7.0:
version "13.7.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857"
integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==

webidl-conversions@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"

Loading…
Cancel
Save