diff --git a/.prettierrc b/.prettierrc
index f4f8cf63..61e643a4 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -12,12 +12,24 @@
"parser": "babel"
}
},
+ {
+ "files": "*.jsx",
+ "options": {
+ "parser": "babel"
+ }
+ },
{
"files": "*.ts",
"options": {
"parser": "babel-ts"
}
},
+ {
+ "files": "*.tsx",
+ "options": {
+ "parser": "babel-ts"
+ }
+ },
{
"files": "*.json",
"options": {
diff --git a/README.md b/README.md
index 9ba23409..265af42a 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,86 @@
# Fake-PEV-Shopping
-Fake Personal Electric Vehicle Shopping application. Browse, compare, buy, review vehicles and their accessories.
+Fake [**P**ersonal **E**lectric **V**ehicle](https://en.wikipedia.org/wiki/Personal_transporter#Types) Shopping application.
+
+>**DISCLAIMER:** this application is meant for **demo purposes only** - it does *NOT* represent a real shop at any moment. Informations about products availability are fake; remaining products informations may be fake or out-of-date. *NO* purchases will actually be sold *NOR* delivered, *NO* payment related actions will be realized - these are only simulated in the application. **Please avoid providing** any of your real personal informations (like logins, passwords, emails, addresses, payment card's PIN or BLIK codes, etc.) on any of the application's pages or views, including any redirections to external services (such as bank related) - **please use fake data** anywhere across the application instead. Application's author does *NOT* take any responsibility for users possible data loss *NOR* actions made by users.
## Table of Contents
-1. Features
-2. Technology stack
-3. [Setup](#setup)
- - [database](#database)
- - frontend
-4. ...
-
-## Setup
-### Database
-This app has been created using MongoDB v4.2.0 with related NPM packages:
-- mongodb v3.5.10
-- mongoose v5.9.27
+1. [Features](#1-features)
+2. [Tech stack](#2-tech-stack)
+3. [Setup](#3-setup)
+ - [automatic (Docker based)](#automatic-setup)
+ - [manual](#manual-setup)
+ - [database](#manual-database-setup)
+ - [app](#manual-app-setup)
+4. [Tests](#4-tests)
+5. [API documentation](#5-api-documentation)
+ - [middleware](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/api-docs/middleware.md)
+ - [database](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/api-docs/database.md)
+ - [frontend](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/api-docs/frontend.md)
+ - [commons](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/api-docs/commons.md)
+6. [Development](#6-development)
+7. [Credits](#7-credits)
+
+## 1. Features
+App offers the following features (with [ideas to add more](https://github.com/ScriptyChris/Fake-PEV-Shopping/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement)):
+- client and seller **user accounts**:
+ - **registering**,
+ - **logging in**,
+ - **resetting password**
+- **searching for products**, including a list of recent searches
+- **browsing** chosen **products** with their data listed, including gallery, reviews and links to related products
+- **listing** available **products**, including:
+ - **filtering** according to alikes: price, category, specifications,
+ - **sorting** and **pagination**
+- **comparing** between multiple products
+- **adding**, **modifying** and **removing** products
+- support for **mobile**, **tablet** and **PC** devices
+- **making orders** for products added to the cart with **various payment and shipment methods**
+- **reviewing** bought products
+## 2. Tech stack
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+App's [frontend](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/src/frontend) is built with [**React**](https://reactjs.org/) (and partial [**TypeScript**](https://typescriptlang.org/) usage). Global state is handled by [**MobX**](https://mobx.js.org/). Layouts are made with a mix of custom [**SCSS**](http://sass-lang.com/) and [**Material-UI**](https://v4.mui.com/). Forms are created with [**Formik**](https://formik.org/). Products shipment via parcels is possible due to [**InPost's Geowidget**](https://dokumentacja-inpost.atlassian.net/wiki/spaces/PL/pages/7438409/Geowidget+v4+User+s+Guide+Old). Frontend is bundled with [**webpack**](http://webpackjs.org/).
+
+Backend is written on [**Node.js**](https://nodejs.org/) in **TypeScript**, with [middleware](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/src/middleware) based on [**Express.js**](https://expressjs.com/) (supporting Rest API) and [database](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/src/database) created with [**MongoDB**](https://www.mongodb.com/) (using [**Mongoose**](https://mongoosejs.com/) as ODM). Authorization is implemented via [**JWT**](https://www.npmjs.com/package/jsonwebtoken) and custom user roles system. Emails to users are send via [**Nodemailer**](https://www.npmjs.com/package/nodemailer). Payments for ordered products are handled by integrated [**PayU API**](https://developers.payu.com/en/).
+
+The app's database and middleware are covered with [*unit* tests](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/test/unit) created with [**Jasmine**](https://jasmine.github.io/). Whole-feature focused scenarios are covered by [*end-to-end* tests](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/test/e2e) created with [**Cypress**](https://www.cypress.io/).
+
+Whole app is contenerized via [**Docker**](https://docker.com/), which helps with easier setup and executing end-to-end tests. Repository is hooked with [**GitHub Actions CI/CD**](https://docs.github.com/en/actions) for integration purposes.
+## 3. Setup
+Regardles of setup method, the app is locally served on [`http://localhost:3000`](http://localhost:3000) by default.
+### Automatic setup
+Whole app can be bootstrapped with [Docker](https://www.docker.com/).
+1. Create `.env` file based on [`.env.example`](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/.env.example).
+2. Navigate to [`./docker`](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/docker) folder with command:
+```sh
+cd docker
+```
+
+3. Start Docker (if your Docker setup requires `sudo` access, you may be prompted to type your password):
+
+*NOTE:* installation downloads and processes a few GB of data, so it may take a while.
+```sh
+sudo docker-compose --env-file ../.env -f docker-compose.yml -f docker-compose.app-standalone-volumes.yml up
+```
+
+This will install all necessary dependencies, populate database with initial data and serve the app.
+
+### Manual setup
+#### Manual database setup
+Database has been created using MongoDB v4.2.0 with [mongodb v3.5.10](https://www.npmjs.com/package/mongodb/v/3.5.10) and [mongoose v5.9.27](https://www.npmjs.com/package/mongoose/v/5.9.27) NPM packages.
To install MongoDB database locally, please download and install it on your machine from this URL: https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2012plus-4.2.9-signed.msi (you can skip first three below steps then) or follow these steps:
1. Go to https://www.mongodb.com/try/download/community
@@ -24,4 +91,65 @@ To install MongoDB database locally, please download and install it on your mach
6. Start the MongoDB running the following command (i assume you are using Windows with default installation path - if not, please adjust the path accordingly)
` C:\Program Files\MongoDB\Server\4.2\bin\mongod.exe --dbpath="absolute_path_to_project_root\database\data"`
-In case of any issues, please refer to the official MongoDB installation guide for your operating system [Windows / Linux / macOS].
+In case of any issues, please refer to the official MongoDB installation guide for your operating system [[Windows](https://docs.mongodb.com/v4.2/tutorial/install-mongodb-on-windows/) / [Linux](https://docs.mongodb.com/v4.2/administration/install-on-linux/) / [macOS](https://docs.mongodb.com/v4.2/tutorial/install-mongodb-on-os-x/)].
+
+#### Manual app setup
+The app building process is based on Node.js v14 LTS and npm, so after [installing it](https://nodejs.org/download/release/latest-fermium/) (optionally via [NVM](https://github.com/nvm-sh/nvm)) do the following:
+1. Install dependencies by command:
+```sh
+npm ci
+```
+2. Build project:
+```sh
+npm build
+```
+3. Create `.env` file based on [`.env.example`](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/.env.example). Change `DATABASE_HOST` variable in `.env` file to `localhost` value.
+
+4. Serve the app:
+```sh
+npm serve
+```
+
+## 4. Tests
+The app contains [**unit** and **end-to-end** tests](#2-tech-stack). You can run them as following:
+- unit tests:
+```sh
+npm run test:unit
+```
+- end-to-end tests:
+
+*NOTE*: it requires [Docker](https://www.docker.com/) installation and `DATABASE_HOST` variable in `.env` file set to `pev-db` value.
+```sh
+npm run test:e2e:dev
+```
+
+## 5. API documentation
+API docs are generated by [**TypeDoc**](https://npmjs.com/package/typedoc), which output is [grouped](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/generate-grouped-api-docs.js) into [a few folders](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/api-docs).
+
+## 6. Development
+If you would like to play with the application's code, [*package.json* file](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/package.json) contains helpful NPM commands, for example:
+- populate database with default initial data and included cleanup (in case you would like to reset database state)
+```sh
+npm run populate-db
+```
+- develop frontend with React's hot module replacement
+```sh
+npm run dev:frontend
+```
+- develop backend with automatic ad-hoc builds
+```sh
+npm run dev:backend
+```
+- debug backend with [Google Chrome's Devtools](https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients) (or compliant tool)
+```sh
+npm run debug
+```
+- generate API documentation based on current source code (with restriction to files listed in [grouping script](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/develop/generate-grouped-api-docs.js))
+```sh
+npm run generate-api-docs
+```
+
+## 7. Credits
+- initial products data is based on the [**eWheels** shop](https://www.ewheels.com/)
+- tech stack icons are provided by [https://github.com/tandpfun/skill-icons](https://github.com/tandpfun/skill-icons)
+- the app's (favicon) icon is provided by [**Icons8**](https://icons8.com)
\ No newline at end of file
diff --git a/api-docs/commons.md b/api-docs/commons.md
new file mode 100644
index 00000000..5500ba8f
--- /dev/null
+++ b/api-docs/commons.md
@@ -0,0 +1,1541 @@
+fake-pev-shopping
+
+# fake-pev-shopping
+
+## Table of contents
+
+### Modules
+
+- [logger](#modulesloggermd)
+- [types](#modulestypesmd)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / [](#modulestypes_internal_md) / StorageService
+
+# Class: StorageService
+
+[types](#modulestypesmd).[](#modulestypes_internal_md).StorageService
+
+## Hierarchy
+
+- **`StorageService`**
+
+ ↳ [`UserCart`](#classestypes_internal_usercartmd)
+
+ ↳ [`UserAccount`](#classestypes_internal_useraccountmd)
+
+ ↳ [`UserAuthToken`](#classestypes_internal_userauthtokenmd)
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new StorageService**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:18](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L18)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`value`, `checkIfShouldRemove`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `value` | [`TStorageValue`](#tstoragevalue) |
+| `checkIfShouldRemove` | () => `boolean` |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:26](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L26)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / [](#modulestypes_internal_md) / StoreService
+
+# Class: StoreService
+
+[types](#modulestypesmd).[](#modulestypes_internal_md).StoreService
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Accessors
+
+- [productComparisonState](#productcomparisonstate)
+- [userAccountState](#useraccountstate)
+- [userCartProducts](#usercartproducts)
+- [userCartProductsCount](#usercartproductscount)
+- [userCartState](#usercartstate)
+- [userCartTotalPrice](#usercarttotalprice)
+
+### Methods
+
+- [addProductToUserCartState](#addproducttousercartstate)
+- [clearProductComparisonState](#clearproductcomparisonstate)
+- [clearProductObservedState](#clearproductobservedstate)
+- [clearUserAccountState](#clearuseraccountstate)
+- [clearUserCartState](#clearusercartstate)
+- [removeProductFromUserCartState](#removeproductfromusercartstate)
+- [replaceUserCartState](#replaceusercartstate)
+- [updateProductComparisonState](#updateproductcomparisonstate)
+- [updateProductObservedState](#updateproductobservedstate)
+- [updateUserAccountState](#updateuseraccountstate)
+
+## Constructors
+
+### constructor
+
+• **new StoreService**()
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:27](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L27)
+
+## Accessors
+
+### productComparisonState
+
+• `get` **productComparisonState**(): [`TUserCartProduct`](#tusercartproduct)[]
+
+#### Returns
+
+[`TUserCartProduct`](#tusercartproduct)[]
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:143](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L143)
+
+___
+
+### userAccountState
+
+• `get` **userAccountState**(): ``null`` \| [`TUserPublic`](#tuserpublic)
+
+#### Returns
+
+``null`` \| [`TUserPublic`](#tuserpublic)
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:139](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L139)
+
+___
+
+### userCartProducts
+
+• `get` **userCartProducts**(): { `_id`: `string` ; `name`: `string` ; `price`: `number` }[]
+
+#### Returns
+
+{ `_id`: `string` ; `name`: `string` ; `price`: `number` }[]
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:127](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L127)
+
+___
+
+### userCartProductsCount
+
+• `get` **userCartProductsCount**(): `number`
+
+#### Returns
+
+`number`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:135](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L135)
+
+___
+
+### userCartState
+
+• `get` **userCartState**(): [`IUserCart`](#interfacestypesiusercartmd)
+
+#### Returns
+
+[`IUserCart`](#interfacestypesiusercartmd)
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:123](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L123)
+
+___
+
+### userCartTotalPrice
+
+• `get` **userCartTotalPrice**(): `number`
+
+#### Returns
+
+`number`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:131](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L131)
+
+## Methods
+
+### addProductToUserCartState
+
+▸ **addProductToUserCartState**(`newUserCartState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `newUserCartState` | [`TUserCartProduct`](#tusercartproduct) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:47](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L47)
+
+___
+
+### clearProductComparisonState
+
+▸ **clearProductComparisonState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:111](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L111)
+
+___
+
+### clearProductObservedState
+
+▸ **clearProductObservedState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:119](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L119)
+
+___
+
+### clearUserAccountState
+
+▸ **clearUserAccountState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:43](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L43)
+
+___
+
+### clearUserCartState
+
+▸ **clearUserCartState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:81](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L81)
+
+___
+
+### removeProductFromUserCartState
+
+▸ **removeProductFromUserCartState**(`newUserCartState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `newUserCartState` | [`TUserCartProduct`](#tusercartproduct) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:61](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L61)
+
+___
+
+### replaceUserCartState
+
+▸ **replaceUserCartState**(`newUserCartState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `newUserCartState` | [`IUserCart`](#interfacestypesiusercartmd) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:88](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L88)
+
+___
+
+### updateProductComparisonState
+
+▸ **updateProductComparisonState**(`__namedParameters`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+| `__namedParameters.add` | [`TUserCartProduct`](#tusercartproduct) |
+| `__namedParameters.remove` | `Partial`<{ `_id`: `string` ; `index`: `number` }\> |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:94](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L94)
+
+___
+
+### updateProductObservedState
+
+▸ **updateProductObservedState**(`observedProductsIDs`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `observedProductsIDs` | `undefined` \| `ObjectId`[] |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:115](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L115)
+
+___
+
+### updateUserAccountState
+
+▸ **updateUserAccountState**(`userAccountState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `userAccountState` | [`TUserPublic`](#tuserpublic) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:39](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L39)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / [](#modulestypes_internal_md) / UserAccount
+
+# Class: UserAccount
+
+[types](#modulestypesmd).[](#modulestypes_internal_md).UserAccount
+
+## Hierarchy
+
+- [`StorageService`](#classestypes_internal_storageservicemd)
+
+ ↳ **`UserAccount`**
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new UserAccount**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Overrides
+
+[StorageService](#classestypes_internal_storageservicemd).[constructor](#constructor)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:70](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L70)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[key](#key)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[get](#get)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[remove](#remove)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`accountState`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `accountState` | [`TUserPublic`](#tuserpublic) |
+
+#### Returns
+
+`void`
+
+#### Overrides
+
+[StorageService](#classestypes_internal_storageservicemd).[update](#update)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:74](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L74)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / [](#modulestypes_internal_md) / UserAuthToken
+
+# Class: UserAuthToken
+
+[types](#modulestypesmd).[](#modulestypes_internal_md).UserAuthToken
+
+## Hierarchy
+
+- [`StorageService`](#classestypes_internal_storageservicemd)
+
+ ↳ **`UserAuthToken`**
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new UserAuthToken**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Overrides
+
+[StorageService](#classestypes_internal_storageservicemd).[constructor](#constructor)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:80](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L80)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[key](#key)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[get](#get)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[remove](#remove)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`authToken`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `authToken` | `string` |
+
+#### Returns
+
+`void`
+
+#### Overrides
+
+[StorageService](#classestypes_internal_storageservicemd).[update](#update)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:84](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L84)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / [](#modulestypes_internal_md) / UserCart
+
+# Class: UserCart
+
+[types](#modulestypesmd).[](#modulestypes_internal_md).UserCart
+
+## Hierarchy
+
+- [`StorageService`](#classestypes_internal_storageservicemd)
+
+ ↳ **`UserCart`**
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new UserCart**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Overrides
+
+[StorageService](#classestypes_internal_storageservicemd).[constructor](#constructor)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:60](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L60)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[key](#key)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[get](#get)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[StorageService](#classestypes_internal_storageservicemd).[remove](#remove)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`cartState`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `cartState` | [`IUserCart`](#interfacestypesiusercartmd) |
+
+#### Returns
+
+`void`
+
+#### Overrides
+
+[StorageService](#classestypes_internal_storageservicemd).[update](#update)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:64](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L64)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / HTTP\_STATUS\_CODE
+
+# Enumeration: HTTP\_STATUS\_CODE
+
+[types](#modulestypesmd).HTTP_STATUS_CODE
+
+## Table of contents
+
+### Enumeration Members
+
+- [BAD\_REQUEST](#bad_request)
+- [CONFLICT](#conflict)
+- [CREATED](#created)
+- [FORBIDDEN](#forbidden)
+- [INTERNAL\_SERVER\_ERROR](#internal_server_error)
+- [NETWORK\_AUTH\_REQUIRED](#network_auth_required)
+- [NOT\_FOUND](#not_found)
+- [NOT\_MODIFIED](#not_modified)
+- [NO\_CONTENT](#no_content)
+- [OK](#ok)
+- [SERVICE\_UNAVAILABLE](#service_unavailable)
+- [UNAUTHORIZED](#unauthorized)
+
+## Enumeration Members
+
+### BAD\_REQUEST
+
+• **BAD\_REQUEST**
+
+#### Defined in
+
+[commons/types.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L42)
+
+___
+
+### CONFLICT
+
+• **CONFLICT**
+
+#### Defined in
+
+[commons/types.ts:46](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L46)
+
+___
+
+### CREATED
+
+• **CREATED**
+
+#### Defined in
+
+[commons/types.ts:38](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L38)
+
+___
+
+### FORBIDDEN
+
+• **FORBIDDEN**
+
+#### Defined in
+
+[commons/types.ts:44](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L44)
+
+___
+
+### INTERNAL\_SERVER\_ERROR
+
+• **INTERNAL\_SERVER\_ERROR**
+
+#### Defined in
+
+[commons/types.ts:47](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L47)
+
+___
+
+### NETWORK\_AUTH\_REQUIRED
+
+• **NETWORK\_AUTH\_REQUIRED**
+
+#### Defined in
+
+[commons/types.ts:49](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L49)
+
+___
+
+### NOT\_FOUND
+
+• **NOT\_FOUND**
+
+#### Defined in
+
+[commons/types.ts:45](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L45)
+
+___
+
+### NOT\_MODIFIED
+
+• **NOT\_MODIFIED**
+
+#### Defined in
+
+[commons/types.ts:41](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L41)
+
+___
+
+### NO\_CONTENT
+
+• **NO\_CONTENT**
+
+#### Defined in
+
+[commons/types.ts:39](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L39)
+
+___
+
+### OK
+
+• **OK**
+
+#### Defined in
+
+[commons/types.ts:37](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L37)
+
+___
+
+### SERVICE\_UNAVAILABLE
+
+• **SERVICE\_UNAVAILABLE**
+
+#### Defined in
+
+[commons/types.ts:48](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L48)
+
+___
+
+### UNAUTHORIZED
+
+• **UNAUTHORIZED**
+
+#### Defined in
+
+[commons/types.ts:43](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L43)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / IOrder
+
+# Interface: IOrder
+
+[types](#modulestypesmd).IOrder
+
+## Table of contents
+
+### Properties
+
+- [paymentType](#paymenttype)
+- [price](#price)
+- [products](#products)
+- [receiver](#receiver)
+- [shipmentType](#shipmenttype)
+
+## Properties
+
+### paymentType
+
+• **paymentType**: ``"Cash"`` \| ``"Card"`` \| ``"Transfer"`` \| ``"BLIK"``
+
+#### Defined in
+
+[commons/types.ts:73](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L73)
+
+___
+
+### price
+
+• **price**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `shipment` | `number` |
+| `total` | `number` |
+
+#### Defined in
+
+[commons/types.ts:75](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L75)
+
+___
+
+### products
+
+• **products**: { `_id`: `string` ; `name`: `string` ; `price`: `number` }[] & { `count`: `number` }[]
+
+#### Defined in
+
+[commons/types.ts:74](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L74)
+
+___
+
+### receiver
+
+• **receiver**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `address` | `string` |
+| `baseInfo` | { `email`: `string` ; `name`: `string` ; `phone`: `string` } |
+| `baseInfo.email` | `string` |
+| `baseInfo.name` | `string` |
+| `baseInfo.phone` | `string` |
+
+#### Defined in
+
+[commons/types.ts:63](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L63)
+
+___
+
+### shipmentType
+
+• **shipmentType**: ``"inPerson"`` \| ``"home"`` \| ``"parcelLocker"``
+
+#### Defined in
+
+[commons/types.ts:71](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L71)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / IPayByLinkMethod
+
+# Interface: IPayByLinkMethod
+
+[types](#modulestypesmd).IPayByLinkMethod
+
+## Table of contents
+
+### Properties
+
+- [maxAmount](#maxamount)
+- [minAmount](#minamount)
+- [name](#name)
+- [status](#status)
+- [type](#type)
+- [value](#value)
+
+## Properties
+
+### maxAmount
+
+• **maxAmount**: `number`
+
+#### Defined in
+
+[commons/types.ts:31](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L31)
+
+___
+
+### minAmount
+
+• **minAmount**: `number`
+
+#### Defined in
+
+[commons/types.ts:30](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L30)
+
+___
+
+### name
+
+• **name**: `string`
+
+#### Defined in
+
+[commons/types.ts:28](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L28)
+
+___
+
+### status
+
+• **status**: ``"ENABLED"`` \| ``"DISABLED"`` \| ``"TEMPORARY_DISABLED"``
+
+#### Defined in
+
+[commons/types.ts:29](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L29)
+
+___
+
+### type
+
+• `Optional` **type**: ``"PBL"`` \| ``"PAYMENT_WALL"``
+
+#### Defined in
+
+[commons/types.ts:26](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L26)
+
+___
+
+### value
+
+• **value**: `string`
+
+#### Defined in
+
+[commons/types.ts:27](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L27)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / IProductInOrder
+
+# Interface: IProductInOrder
+
+[types](#modulestypesmd).IProductInOrder
+
+## Table of contents
+
+### Properties
+
+- [name](#name)
+- [quantity](#quantity)
+- [unitPrice](#unitprice)
+
+## Properties
+
+### name
+
+• **name**: `string`
+
+#### Defined in
+
+[commons/types.ts:20](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L20)
+
+___
+
+### quantity
+
+• **quantity**: `number`
+
+#### Defined in
+
+[commons/types.ts:22](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L22)
+
+___
+
+### unitPrice
+
+• **unitPrice**: `number`
+
+#### Defined in
+
+[commons/types.ts:21](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L21)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / IUserCart
+
+# Interface: IUserCart
+
+[types](#modulestypesmd).IUserCart
+
+## Table of contents
+
+### Properties
+
+- [products](#products)
+- [totalCount](#totalcount)
+- [totalPrice](#totalprice)
+
+## Properties
+
+### products
+
+• **products**: { `_id`: `string` ; `name`: `string` ; `price`: `number` }[]
+
+#### Defined in
+
+[commons/types.ts:53](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L53)
+
+___
+
+### totalCount
+
+• **totalCount**: `number`
+
+#### Defined in
+
+[commons/types.ts:58](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L58)
+
+___
+
+### totalPrice
+
+• **totalPrice**: `number`
+
+#### Defined in
+
+[commons/types.ts:59](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L59)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / [](#modulestypes_internal_md) / ICustomResExt
+
+# Interface: ICustomResExt
+
+[types](#modulestypesmd).[](#modulestypes_internal_md).ICustomResExt
+
+## Table of contents
+
+### Properties
+
+- [\_\_ERROR\_TO\_HANDLE](#__error_to_handle)
+- [\_\_EXCEPTION\_ALREADY\_HANDLED](#__exception_already_handled)
+- [\_\_NO\_CONTENT](#__no_content)
+
+## Properties
+
+### \_\_ERROR\_TO\_HANDLE
+
+• **\_\_ERROR\_TO\_HANDLE**: `Pick`<[`IEmbracedResponse`](#interfacestypes_internal_iembracedresponsemd)<`never`\>, ``"error"``\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:570](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L570)
+
+___
+
+### \_\_EXCEPTION\_ALREADY\_HANDLED
+
+• **\_\_EXCEPTION\_ALREADY\_HANDLED**: ``true``
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:571](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L571)
+
+___
+
+### \_\_NO\_CONTENT
+
+• **\_\_NO\_CONTENT**: ``true``
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:569](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L569)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) / [](#modulestypes_internal_md) / IEmbracedResponse
+
+# Interface: IEmbracedResponse
+
+[types](#modulestypesmd).[](#modulestypes_internal_md).IEmbracedResponse
+
+## Type parameters
+
+| Name | Type |
+| :------ | :------ |
+| `PayloadType` | `never` |
+
+## Table of contents
+
+### Properties
+
+- [authToken](#authtoken)
+- [error](#error)
+- [exception](#exception)
+- [message](#message)
+- [payload](#payload)
+
+## Properties
+
+### authToken
+
+• **authToken**: ``null`` \| `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:11](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L11)
+
+___
+
+### error
+
+• **error**: `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L14)
+
+___
+
+### exception
+
+• **exception**: `Error` \| { `message`: `string` ; `stack?`: `string` }
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:15](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L15)
+
+___
+
+### message
+
+• **message**: `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:13](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L13)
+
+___
+
+### payload
+
+• **payload**: `unknown`[] \| `PayloadType` \| `Record`<`string`, `unknown`\>
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:12](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L12)
+
+[fake-pev-shopping](#readmemd) / [logger](#modulesloggermd) /
+
+# Namespace:
+
+[logger](#modulesloggermd).
+
+[fake-pev-shopping](#readmemd) / logger
+
+# Module: logger
+
+Custom wrapper for a commonly used global `console` methods.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#moduleslogger_internal_md)
+
+### Type Aliases
+
+- [TLogger](#tlogger)
+
+### Functions
+
+- [getLogger](#getlogger)
+
+## Type Aliases
+
+### TLogger
+
+Ƭ **TLogger**: `Logger`
+
+#### Defined in
+
+[commons/logger.ts:72](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/logger.ts#L72)
+
+## Functions
+
+### getLogger
+
+▸ **getLogger**(`moduleFileName`): `Logger`
+
+Creates a module bound logger, which name will be visually emphased in output logs.
+
+**`example`** Log output for `middleware-index` module
+([Module: middleware-index.js]):: Server is listening on port 3000
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `moduleFileName` | `string` |
+
+#### Returns
+
+`Logger`
+
+#### Defined in
+
+[commons/logger.ts:62](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/logger.ts#L62)
+
+[fake-pev-shopping](#readmemd) / [types](#modulestypesmd) /
+
+# Namespace:
+
+[types](#modulestypesmd).
+
+## Table of contents
+
+### Classes
+
+- [StorageService](#classestypes_internal_storageservicemd)
+- [StoreService](#classestypes_internal_storeservicemd)
+- [UserAccount](#classestypes_internal_useraccountmd)
+- [UserAuthToken](#classestypes_internal_userauthtokenmd)
+- [UserCart](#classestypes_internal_usercartmd)
+
+### Interfaces
+
+- [ICustomResExt](#interfacestypes_internal_icustomresextmd)
+- [IEmbracedResponse](#interfacestypes_internal_iembracedresponsemd)
+
+### Type Aliases
+
+- [TStorageValue](#tstoragevalue)
+- [TUserCartProduct](#tusercartproduct)
+- [TUserPublic](#tuserpublic)
+
+### Variables
+
+- [storageService](#storageservice)
+- [storeService](#storeservice)
+- [userSessionService](#usersessionservice)
+
+## Type Aliases
+
+### TStorageValue
+
+Ƭ **TStorageValue**: [`IUserCart`](#interfacestypesiusercartmd) \| [`TUserPublic`](#tuserpublic) \| `NonNullable`<`IUser`[``"tokens"``][``"auth"``]\>[`number`] \| ``null``
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:9](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L9)
+
+___
+
+### TUserCartProduct
+
+Ƭ **TUserCartProduct**: [`IUserCart`](#interfacestypesiusercartmd)[``"products"``][`number`] & { `count`: `number` }
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:17](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L17)
+
+___
+
+### TUserPublic
+
+Ƭ **TUserPublic**: `Pick`<`IUser`, ``"login"`` \| ``"email"`` \| ``"observedProductsIDs"``\> & { `_id`: `Schema.Types.ObjectId` ; `accountType`: `NonNullable`<`IUser`[``"accountType"``]\>[``"roleName"``] }
+
+#### Defined in
+
+[src/database/models/_user.ts:242](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L242)
+
+## Variables
+
+### storageService
+
+• `Const` **storageService**: `Object`
+
+Manipulating storage data API for various contexts, such as `UserCart` or `UserAccount`.
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `userAccount` | [`UserAccount`](#classestypes_internal_useraccountmd) |
+| `userAuthToken` | [`UserAuthToken`](#classestypes_internal_userauthtokenmd) |
+| `userCart` | [`UserCart`](#classestypes_internal_usercartmd) |
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L14)
+
+___
+
+### storeService
+
+• `Const` **storeService**: [`StoreService`](#classestypes_internal_storeservicemd)
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:169](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L169)
+
+___
+
+### userSessionService
+
+• `Const` **userSessionService**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `logIn` | (`logInCredentials`: `Pick`<`IUser`, ``"login"`` \| ``"password"``\>) => `Promise`<[`TUserPublic`](#tuserpublic) \| `Pick`<[`ICustomResExt`](#interfacestypes_internal_icustomresextmd), ``"__EXCEPTION_ALREADY_HANDLED"``\>\> |
+| `logOut` | () => `Promise`<`Pick`<[`ICustomResExt`](#interfacestypes_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacestypes_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacestypes_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\> |
+| `logOutFromMultipleSessions` | (`shouldPreserveCurrentSession`: `boolean`) => `Promise`<`Pick`<[`ICustomResExt`](#interfacestypes_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacestypes_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacestypes_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\> |
+| `restoreSession` | () => `void` |
+
+#### Defined in
+
+[src/frontend/features/userSessionService.ts:12](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/userSessionService.ts#L12)
+
+[fake-pev-shopping](#readmemd) / types
+
+# Module: types
+
+Common types for whole app.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulestypes_internal_md)
+
+### Enumerations
+
+- [HTTP\_STATUS\_CODE](#enumstypeshttp_status_codemd)
+
+### Interfaces
+
+- [IOrder](#interfacestypesiordermd)
+- [IPayByLinkMethod](#interfacestypesipaybylinkmethodmd)
+- [IProductInOrder](#interfacestypesiproductinordermd)
+- [IUserCart](#interfacestypesiusercartmd)
+
+### Type Aliases
+
+- [TPagination](#tpagination)
+
+## Type Aliases
+
+### TPagination
+
+Ƭ **TPagination**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `pageNumber` | `number` |
+| `productsPerPage` | `number` |
+
+#### Defined in
+
+[commons/types.ts:81](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L81)
diff --git a/api-docs/database.md b/api-docs/database.md
new file mode 100644
index 00000000..3658adf0
--- /dev/null
+++ b/api-docs/database.md
@@ -0,0 +1,575 @@
+fake-pev-shopping
+
+# fake-pev-shopping
+
+## Table of contents
+
+### Modules
+
+- [api](#modulesapimd)
+- [models](#modulesmodelsmd)
+- [populate/populate](#modulespopulate_populatemd)
+
+[fake-pev-shopping](#readmemd) / [api](#modulesapimd) /
+
+# Namespace:
+
+[api](#modulesapimd).
+
+## Table of contents
+
+### Type Aliases
+
+- [TPaginateModel](#tpaginatemodel)
+- [TPaginationConfig](#tpaginationconfig)
+
+### Functions
+
+- [getPaginatedItems](#getpaginateditems)
+
+## Type Aliases
+
+### TPaginateModel
+
+Ƭ **TPaginateModel**: `PaginateModel`<[`TDocuments`](#tdocuments)\>
+
+#### Defined in
+
+[src/database/utils/paginateItemsFromDB.ts:26](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/utils/paginateItemsFromDB.ts#L26)
+
+___
+
+### TPaginationConfig
+
+Ƭ **TPaginationConfig**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `limit` | `number` |
+| `page` | `number` |
+
+#### Defined in
+
+[src/database/utils/paginateItemsFromDB.ts:25](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/utils/paginateItemsFromDB.ts#L25)
+
+## Functions
+
+### getPaginatedItems
+
+▸ **getPaginatedItems**(`__namedParameters`, `itemQuery`, `projection`): `Promise`<`PaginateResult`<`IProduct` \| `IUser` \| `IUserRole`\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+| `__namedParameters.Model` | [`TPaginateModel`](#tpaginatemodel) |
+| `__namedParameters.pagination` | [`TPaginationConfig`](#tpaginationconfig) |
+| `__namedParameters.sort?` | [`TSort`](#tsort) |
+| `itemQuery` | `undefined` \| `MongooseFilterQuery`<`Pick`<`IProduct` \| `IUser` \| `IUserRole`, ``"_id"``\>\> |
+| `projection` | `any` |
+
+#### Returns
+
+`Promise`<`PaginateResult`<`IProduct` \| `IUser` \| `IUserRole`\>\>
+
+#### Defined in
+
+[src/database/utils/paginateItemsFromDB.ts:5](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/utils/paginateItemsFromDB.ts#L5)
+
+[fake-pev-shopping](#readmemd) / api
+
+# Module: api
+
+Facade over database CRUD operations.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesapi_internal_md)
+
+### Functions
+
+- [deleteFromDB](#deletefromdb)
+- [getFromDB](#getfromdb)
+- [saveToDB](#savetodb)
+- [updateOneModelInDB](#updateonemodelindb)
+
+## Functions
+
+### deleteFromDB
+
+▸ **deleteFromDB**(`modelName`, `fieldValue`): `Promise`<{} & { `deletedCount?`: `number` }\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `modelName` | ``"Product"`` \| ``"User"`` \| ``"User_Role"`` |
+| `fieldValue` | `string` \| `RegExp` |
+
+#### Returns
+
+`Promise`<{} & { `deletedCount?`: `number` }\>
+
+#### Defined in
+
+[src/database/api.ts:150](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/api.ts#L150)
+
+___
+
+### getFromDB
+
+▸ **getFromDB**<`T`\>(`config`, `itemQuery`, `projection?`): `Promise`<`T` \| `ReturnType` \| `ReturnType` \| ``null``\>
+
+#### Type parameters
+
+| Name | Type |
+| :------ | :------ |
+| `T` | extends `IProduct` \| `IUser` \| `IUserRole` |
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `config` | `Object` |
+| `config.findMultiple?` | `boolean` |
+| `config.isDistinct?` | `boolean` |
+| `config.modelName` | ``"Product"`` \| ``"User"`` \| ``"User_Role"`` |
+| `config.pagination?` | [`TPaginationConfig`](#tpaginationconfig) |
+| `config.population?` | `string` \| `ModelPopulateOptions` \| `ModelPopulateOptions`[] |
+| `config.sort?` | [`TSort`](#tsort) |
+| `itemQuery` | `string` \| `MongooseFilterQuery`<`Pick`<`unknown`, `never`\>\> |
+| `projection?` | `unknown` |
+
+#### Returns
+
+`Promise`<`T` \| `ReturnType` \| `ReturnType` \| ``null``\>
+
+#### Defined in
+
+[src/database/api.ts:38](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/api.ts#L38)
+
+___
+
+### saveToDB
+
+▸ **saveToDB**(`modelName`, `itemData`): `Promise`<`IProduct` \| `IUser` \| `IUserRole`\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `modelName` | ``"Product"`` \| ``"User"`` \| ``"User_Role"`` |
+| `itemData` | `unknown` |
+
+#### Returns
+
+`Promise`<`IProduct` \| `IUser` \| `IUserRole`\>
+
+#### Defined in
+
+[src/database/api.ts:25](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/api.ts#L25)
+
+___
+
+### updateOneModelInDB
+
+▸ **updateOneModelInDB**(`modelName`, `itemQuery`, `updateData`): `Promise`<``null`` \| `IProduct` \| `IUser` \| `IUserRole`\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `modelName` | ``"Product"`` \| ``"User"`` \| ``"User_Role"`` |
+| `itemQuery` | `string` \| `MongooseFilterQuery`<`Pick`<`IProduct`, ``"technicalSpecs"`` \| ``"_id"`` \| ``"name"`` \| ``"url"`` \| ``"category"`` \| ``"price"`` \| ``"shortDescription"`` \| ``"images"`` \| ``"relatedProductsNames"`` \| ``"reviews"`` \| ``"prepareUrlFieldBasedOnNameField"``\>\> \| `MongooseFilterQuery`<`Pick`<`IUser`, ``"_id"`` \| ``"login"`` \| ``"email"`` \| ``"observedProductsIDs"`` \| ``"password"`` \| ``"isConfirmed"`` \| ``"tokens"`` \| ``"accountType"`` \| ``"generateAuthToken"`` \| ``"matchPassword"`` \| ``"setSingleToken"`` \| ``"deleteSingleToken"`` \| ``"confirmUser"`` \| ``"addProductToObserved"`` \| ``"removeProductFromObserved"`` \| ``"removeAllProductsFromObserved"``\>\> \| `MongooseFilterQuery`<`Pick`<`IUserRole`, ``"_id"`` \| ``"roleName"`` \| ``"owners"``\>\> |
+| `updateData` | `Object` |
+| `updateData.action` | `string` |
+| `updateData.data` | `unknown` |
+
+#### Returns
+
+`Promise`<``null`` \| `IProduct` \| `IUser` \| `IUserRole`\>
+
+#### Defined in
+
+[src/database/api.ts:110](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/api.ts#L110)
+
+[fake-pev-shopping](#readmemd) / [models](#modulesmodelsmd) /
+
+# Namespace:
+
+[models](#modulesmodelsmd).
+
+[fake-pev-shopping](#readmemd) / models
+
+# Module: models
+
+Groups and re-exports lower level types and values related to working with database'es models.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesmodels_internal_md)
+
+### Type Aliases
+
+- [TCOLLECTION\_NAMES](#tcollection_names)
+- [TDocuments](#tdocuments)
+- [TProductModel](#tproductmodel)
+- [TProductPublic](#tproductpublic)
+- [TProductToPopulate](#tproducttopopulate)
+- [TSort](#tsort)
+- [TUserModel](#tusermodel)
+- [TUserPublic](#tuserpublic)
+- [TUserRegistrationCredentials](#tuserregistrationcredentials)
+- [TUserRoleModel](#tuserrolemodel)
+- [TUserRoleName](#tuserrolename)
+- [TUserRoleToPopulate](#tuserroletopopulate)
+- [TUserToPopulate](#tusertopopulate)
+
+### Variables
+
+- [COLLECTION\_NAMES](#collection_names)
+- [ProductModel](#productmodel)
+- [USER\_ROLES\_MAP](#user_roles_map)
+- [UserModel](#usermodel)
+- [UserRoleModel](#userrolemodel)
+
+### Functions
+
+- [getModel](#getmodel)
+- [isValidObjectId](#isvalidobjectid)
+
+## Type Aliases
+
+### TCOLLECTION\_NAMES
+
+Ƭ **TCOLLECTION\_NAMES**: keyof typeof [`COLLECTION_NAMES`](#collection_names)
+
+#### Defined in
+
+[src/database/models/__core-and-commons.ts:17](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/__core-and-commons.ts#L17)
+
+___
+
+### TDocuments
+
+Ƭ **TDocuments**: `IProduct` \| `IUser` \| `IUserRole`
+
+#### Defined in
+
+[src/database/models/index.ts:18](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/index.ts#L18)
+
+___
+
+### TProductModel
+
+Ƭ **TProductModel**: typeof [`ProductModel`](#productmodel)
+
+#### Defined in
+
+[src/database/models/_product.ts:155](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_product.ts#L155)
+
+___
+
+### TProductPublic
+
+Ƭ **TProductPublic**: `Pick`<`IProduct`, ``"name"`` \| ``"url"`` \| ``"category"`` \| ``"price"`` \| ``"shortDescription"`` \| ``"technicalSpecs"`` \| ``"relatedProductsNames"``\>
+
+#### Defined in
+
+[src/database/models/_product.ts:157](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_product.ts#L157)
+
+___
+
+### TProductToPopulate
+
+Ƭ **TProductToPopulate**: `Exclude`<`IProduct`, ``"prepareUrlFieldBasedOnNameField"``\>
+
+#### Defined in
+
+[src/database/models/_product.ts:162](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_product.ts#L162)
+
+___
+
+### TSort
+
+Ƭ **TSort**: `Object`
+
+#### Index signature
+
+▪ [key: `string`]: ``1`` \| ``-1``
+
+#### Defined in
+
+[src/database/models/index.ts:19](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/index.ts#L19)
+
+___
+
+### TUserModel
+
+Ƭ **TUserModel**: typeof [`UserModel`](#usermodel)
+
+#### Defined in
+
+[src/database/models/_user.ts:240](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L240)
+
+___
+
+### TUserPublic
+
+Ƭ **TUserPublic**: `Pick`<`IUser`, ``"login"`` \| ``"email"`` \| ``"observedProductsIDs"``\> & { `_id`: `Schema.Types.ObjectId` ; `accountType`: `NonNullable`<`IUser`[``"accountType"``]\>[``"roleName"``] }
+
+#### Defined in
+
+[src/database/models/_user.ts:242](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L242)
+
+___
+
+### TUserRegistrationCredentials
+
+Ƭ **TUserRegistrationCredentials**: `Pick`<`IUser`, ``"login"`` \| ``"password"`` \| ``"email"``\> & { `repeatedPassword`: `IUser`[``"password"``] }
+
+#### Defined in
+
+[src/database/models/_user.ts:285](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L285)
+
+___
+
+### TUserRoleModel
+
+Ƭ **TUserRoleModel**: typeof [`UserRoleModel`](#userrolemodel)
+
+#### Defined in
+
+[src/database/models/_userRole.ts:39](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_userRole.ts#L39)
+
+___
+
+### TUserRoleName
+
+Ƭ **TUserRoleName**: keyof typeof [`USER_ROLES_MAP`](#user_roles_map)
+
+#### Defined in
+
+[src/database/models/__core-and-commons.ts:24](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/__core-and-commons.ts#L24)
+
+___
+
+### TUserRoleToPopulate
+
+Ƭ **TUserRoleToPopulate**: `Omit`<`IUserRole`, keyof `Document`\>
+
+#### Defined in
+
+[src/database/models/_userRole.ts:49](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_userRole.ts#L49)
+
+___
+
+### TUserToPopulate
+
+Ƭ **TUserToPopulate**: `Pick`<`IUser`, ``"login"`` \| ``"password"`` \| ``"email"`` \| ``"isConfirmed"``\> & { `__accountType`: [`TUserRoleName`](#tuserrolename) }
+
+#### Defined in
+
+[src/database/models/_user.ts:247](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L247)
+
+## Variables
+
+### COLLECTION\_NAMES
+
+• `Const` **COLLECTION\_NAMES**: `Readonly`<{ `Product`: ``"Product"`` = 'Product'; `User`: ``"User"`` = 'User'; `User_Role`: ``"User_Role"`` = 'User\_Role' }\>
+
+#### Defined in
+
+[src/database/models/__core-and-commons.ts:12](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/__core-and-commons.ts#L12)
+
+___
+
+### ProductModel
+
+• `Const` **ProductModel**: `Model`<`IProduct`, {}\>
+
+#### Defined in
+
+[src/database/models/_product.ts:154](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_product.ts#L154)
+
+___
+
+### USER\_ROLES\_MAP
+
+• `Const` **USER\_ROLES\_MAP**: `Readonly`<{ `client`: ``"client"`` = 'client'; `seller`: ``"seller"`` = 'seller' }\>
+
+#### Defined in
+
+[src/database/models/__core-and-commons.ts:20](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/__core-and-commons.ts#L20)
+
+___
+
+### UserModel
+
+• `Const` **UserModel**: `IUserModel`
+
+#### Defined in
+
+[src/database/models/_user.ts:239](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L239)
+
+___
+
+### UserRoleModel
+
+• `Const` **UserRoleModel**: `Model`<`IUserRole`, {}\>
+
+#### Defined in
+
+[src/database/models/_userRole.ts:38](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_userRole.ts#L38)
+
+## Functions
+
+### getModel
+
+▸ **getModel**<`T`\>(`modelName`): { `Product`: `Model`<`IProduct`, {}\> = ProductModel; `User`: `IUserModel` = UserModel; `User_Role`: `Model`<`IUserRole`, {}\> = UserRoleModel }[`T`]
+
+#### Type parameters
+
+| Name | Type |
+| :------ | :------ |
+| `T` | extends ``"Product"`` \| ``"User"`` \| ``"User_Role"`` |
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `modelName` | `T` |
+
+#### Returns
+
+{ `Product`: `Model`<`IProduct`, {}\> = ProductModel; `User`: `IUserModel` = UserModel; `User_Role`: `Model`<`IUserRole`, {}\> = UserRoleModel }[`T`]
+
+#### Defined in
+
+[src/database/models/index.ts:17](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/index.ts#L17)
+
+___
+
+### isValidObjectId
+
+▸ **isValidObjectId**(`value`): `boolean`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `value` | `any` |
+
+#### Returns
+
+`boolean`
+
+#### Defined in
+
+[src/database/models/__core-and-commons.ts:8](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/__core-and-commons.ts#L8)
+
+[fake-pev-shopping](#readmemd) / populate/populate
+
+# Module: populate/populate
+
+Populates database with indicated initial data, optionally doing a cleanup beforehand.
+
+**`example`** npm usage
+```sh
+npm run populate-db
+```
+
+**`example`** Manual CLI usage
+```sh
+ts-node src/database/populate/populate.tspopulate.ts \
+ executedFromCLI=true \
+ products__InputPath=path/to/JSON/with/initial/products/data
+```
+
+## Table of contents
+
+### Variables
+
+- [DEFAULT\_PARAMS](#default_params)
+- [PARAMS](#params)
+
+### Functions
+
+- [executeDBPopulation](#executedbpopulation)
+
+## Variables
+
+### DEFAULT\_PARAMS
+
+• `Const` **DEFAULT\_PARAMS**: `Object`
+
+Maps default params, which are applied when regarding individual params are not provided via CLI.
+
+**`notexported`**
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `cleanAllBefore` | ``"true"`` |
+| `products__InputPath` | ``"./initialData/products.json"`` |
+| `user_roles__InputPath` | ``"./initialData/user_roles.json"`` |
+| `users__InputPath` | ``"./initialData/users.json"`` |
+
+#### Defined in
+
+[src/database/populate/populate.ts:48](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/populate/populate.ts#L48)
+
+___
+
+### PARAMS
+
+• `Const` **PARAMS**: `Object`
+
+Maps supported params passed via CLI.
+
+**`notexported`**
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `CLEAN_ALL_BEFORE` | ``"cleanAllBefore"`` |
+| `EXECUTED_FROM_CLI` | ``"executedFromCLI"`` |
+| `JSON_FILE_PATH` | { `PRODUCTS`: ``"products__InputPath"`` = 'products\_\_InputPath'; `USERS`: ``"users__InputPath"`` = 'users\_\_InputPath'; `USER_ROLES`: ``"user_roles__InputPath"`` = 'user\_roles\_\_InputPath' } |
+| `JSON_FILE_PATH.PRODUCTS` | ``"products__InputPath"`` |
+| `JSON_FILE_PATH.USERS` | ``"users__InputPath"`` |
+| `JSON_FILE_PATH.USER_ROLES` | ``"user_roles__InputPath"`` |
+
+#### Defined in
+
+[src/database/populate/populate.ts:35](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/populate/populate.ts#L35)
+
+## Functions
+
+### executeDBPopulation
+
+▸ **executeDBPopulation**(`shouldCleanupAll?`): `Promise`<`boolean`\>
+
+Executes database population. May be called from other module or it's automatically called when this script is run from CLI.
+
+#### Parameters
+
+| Name | Type | Default value | Description |
+| :------ | :------ | :------ | :------ |
+| `shouldCleanupAll` | `boolean` | `false` | Decides whether do database cleanup. Passing `PARAMS.CLEAN_ALL_BEFORE` via CLI is an alternative way to do cleanup. |
+
+#### Returns
+
+`Promise`<`boolean`\>
+
+#### Defined in
+
+[src/database/populate/populate.ts:117](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/populate/populate.ts#L117)
diff --git a/api-docs/frontend.md b/api-docs/frontend.md
new file mode 100644
index 00000000..309956fa
--- /dev/null
+++ b/api-docs/frontend.md
@@ -0,0 +1,2787 @@
+fake-pev-shopping
+
+# fake-pev-shopping
+
+## Table of contents
+
+### Modules
+
+- [components/pages/\_routes](#modulescomponents_pages__routesmd)
+- [components/utils/bodyObserver](#modulescomponents_utils_bodyobservermd)
+- [components/utils/flexibleList](#modulescomponents_utils_flexiblelistmd)
+- [components/utils/pagination](#modulescomponents_utils_paginationmd)
+- [components/utils/pevElements](#modulescomponents_utils_pevelementsmd)
+- [components/utils/popup](#modulescomponents_utils_popupmd)
+- [components/utils/ratingWidget](#modulescomponents_utils_ratingwidgetmd)
+- [components/utils/scroller](#modulescomponents_utils_scrollermd)
+- [contexts/rwd-layout](#modulescontexts_rwd_layoutmd)
+- [features/httpService](#modulesfeatures_httpservicemd)
+- [features/storageService](#modulesfeatures_storageservicemd)
+- [features/storeService](#modulesfeatures_storeservicemd)
+- [features/userSessionService](#modulesfeatures_usersessionservicemd)
+
+[fake-pev-shopping](#readmemd) / [components/pages/\_routes](#modulescomponents_pages__routesmd) / [](#modulescomponents_pages__routes_internal_md) / StoreService
+
+# Class: StoreService
+
+[components/pages/_routes](#modulescomponents_pages__routesmd).[](#modulescomponents_pages__routes_internal_md).StoreService
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Accessors
+
+- [productComparisonState](#productcomparisonstate)
+- [userAccountState](#useraccountstate)
+- [userCartProducts](#usercartproducts)
+- [userCartProductsCount](#usercartproductscount)
+- [userCartState](#usercartstate)
+- [userCartTotalPrice](#usercarttotalprice)
+
+### Methods
+
+- [addProductToUserCartState](#addproducttousercartstate)
+- [clearProductComparisonState](#clearproductcomparisonstate)
+- [clearProductObservedState](#clearproductobservedstate)
+- [clearUserAccountState](#clearuseraccountstate)
+- [clearUserCartState](#clearusercartstate)
+- [removeProductFromUserCartState](#removeproductfromusercartstate)
+- [replaceUserCartState](#replaceusercartstate)
+- [updateProductComparisonState](#updateproductcomparisonstate)
+- [updateProductObservedState](#updateproductobservedstate)
+- [updateUserAccountState](#updateuseraccountstate)
+
+## Constructors
+
+### constructor
+
+• **new StoreService**()
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:27](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L27)
+
+## Accessors
+
+### productComparisonState
+
+• `get` **productComparisonState**(): [`TUserCartProduct`](#tusercartproduct)[]
+
+#### Returns
+
+[`TUserCartProduct`](#tusercartproduct)[]
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:143](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L143)
+
+___
+
+### userAccountState
+
+• `get` **userAccountState**(): ``null`` \| [`TUserPublic`](#tuserpublic)
+
+#### Returns
+
+``null`` \| [`TUserPublic`](#tuserpublic)
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:139](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L139)
+
+___
+
+### userCartProducts
+
+• `get` **userCartProducts**(): { `_id`: `string` ; `name`: `string` ; `price`: `number` }[]
+
+#### Returns
+
+{ `_id`: `string` ; `name`: `string` ; `price`: `number` }[]
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:127](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L127)
+
+___
+
+### userCartProductsCount
+
+• `get` **userCartProductsCount**(): `number`
+
+#### Returns
+
+`number`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:135](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L135)
+
+___
+
+### userCartState
+
+• `get` **userCartState**(): [`IUserCart`](#interfacescomponents_pages__routes_internal_iusercartmd)
+
+#### Returns
+
+[`IUserCart`](#interfacescomponents_pages__routes_internal_iusercartmd)
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:123](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L123)
+
+___
+
+### userCartTotalPrice
+
+• `get` **userCartTotalPrice**(): `number`
+
+#### Returns
+
+`number`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:131](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L131)
+
+## Methods
+
+### addProductToUserCartState
+
+▸ **addProductToUserCartState**(`newUserCartState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `newUserCartState` | [`TUserCartProduct`](#tusercartproduct) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:47](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L47)
+
+___
+
+### clearProductComparisonState
+
+▸ **clearProductComparisonState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:111](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L111)
+
+___
+
+### clearProductObservedState
+
+▸ **clearProductObservedState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:119](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L119)
+
+___
+
+### clearUserAccountState
+
+▸ **clearUserAccountState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:43](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L43)
+
+___
+
+### clearUserCartState
+
+▸ **clearUserCartState**(): `void`
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:81](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L81)
+
+___
+
+### removeProductFromUserCartState
+
+▸ **removeProductFromUserCartState**(`newUserCartState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `newUserCartState` | [`TUserCartProduct`](#tusercartproduct) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:61](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L61)
+
+___
+
+### replaceUserCartState
+
+▸ **replaceUserCartState**(`newUserCartState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `newUserCartState` | [`IUserCart`](#interfacescomponents_pages__routes_internal_iusercartmd) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:88](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L88)
+
+___
+
+### updateProductComparisonState
+
+▸ **updateProductComparisonState**(`__namedParameters`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+| `__namedParameters.add` | [`TUserCartProduct`](#tusercartproduct) |
+| `__namedParameters.remove` | `Partial`<{ `_id`: `string` ; `index`: `number` }\> |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:94](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L94)
+
+___
+
+### updateProductObservedState
+
+▸ **updateProductObservedState**(`observedProductsIDs`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `observedProductsIDs` | `undefined` \| `ObjectId`[] |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:115](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L115)
+
+___
+
+### updateUserAccountState
+
+▸ **updateUserAccountState**(`userAccountState`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `userAccountState` | [`TUserPublic`](#tuserpublic) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:39](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L39)
+
+[fake-pev-shopping](#readmemd) / [features/httpService](#modulesfeatures_httpservicemd) / [](#modulesfeatures_httpservice_internal_md) / Ajax
+
+# Class: Ajax
+
+[features/httpService](#modulesfeatures_httpservicemd).[](#modulesfeatures_httpservice_internal_md).Ajax
+
+Handles (low level) HTTP actions as:
+- setting appropriate headers,
+- assembling requests regarding URL, params, payload, etc. according to used HTTP method and backend expectance,
+- initially parsing responses,
+- initially handling HTTP errors.
+
+## Hierarchy
+
+- **`Ajax`**
+
+ ↳ [`HttpService`](#classesfeatures_httpservice_internal_httpservicemd)
+
+[fake-pev-shopping](#readmemd) / [features/httpService](#modulesfeatures_httpservicemd) / [](#modulesfeatures_httpservice_internal_md) / HttpService
+
+# Class: HttpService
+
+[features/httpService](#modulesfeatures_httpservicemd).[](#modulesfeatures_httpservice_internal_md).HttpService
+
+Intermediates (high level) client actions meant to communicate with backend APIs.
+
+## Hierarchy
+
+- [`Ajax`](#classesfeatures_httpservice_internal_ajaxmd)
+
+ ↳ **`HttpService`**
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [URLS](#urls)
+
+### Methods
+
+- [\_preparePaginationParams](#_preparepaginationparams)
+- [addProduct](#addproduct)
+- [addProductReview](#addproductreview)
+- [addProductToObserved](#addproducttoobserved)
+- [changePassword](#changepassword)
+- [confirmRegistration](#confirmregistration)
+- [deleteProduct](#deleteproduct)
+- [getCurrentUser](#getcurrentuser)
+- [getObservedProducts](#getobservedproducts)
+- [getProductByUrl](#getproductbyurl)
+- [getProductCategories](#getproductcategories)
+- [getProducts](#getproducts)
+- [getProductsById](#getproductsbyid)
+- [getProductsByName](#getproductsbyname)
+- [getProductsByNames](#getproductsbynames)
+- [getProductsSpecifications](#getproductsspecifications)
+- [getUserRoles](#getuserroles)
+- [logOutUserFromSessions](#logoutuserfromsessions)
+- [loginUser](#loginuser)
+- [logoutUser](#logoutuser)
+- [makeOrder](#makeorder)
+- [modifyProduct](#modifyproduct)
+- [registerUser](#registeruser)
+- [removeAllProductsFromObserved](#removeallproductsfromobserved)
+- [removeProductFromObserved](#removeproductfromobserved)
+- [resendConfirmRegistration](#resendconfirmregistration)
+- [resendResetPassword](#resendresetpassword)
+- [resetPassword](#resetpassword)
+- [setNewPassword](#setnewpassword)
+
+## Constructors
+
+### constructor
+
+• **new HttpService**()
+
+#### Overrides
+
+Ajax.constructor
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:236](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L236)
+
+## Properties
+
+### URLS
+
+• `Private` **URLS**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `ORDERS` | ``"orders"`` |
+| `PRODUCTS` | ``"products"`` |
+| `PRODUCTS_SPECS` | ``"products/specs"`` |
+| `PRODUCT_CATEGORIES` | ``"productCategories"`` |
+| `USERS` | ``"users"`` |
+| `USER_ROLES` | ``"user-roles"`` |
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:227](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L227)
+
+## Methods
+
+### \_preparePaginationParams
+
+▸ **_preparePaginationParams**(`searchParams`, `pagination?`): `void`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `searchParams` | `URLSearchParams` |
+| `pagination?` | [`TPagination`](#tpagination) |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:240](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L240)
+
+___
+
+### addProduct
+
+▸ **addProduct**(`product`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Adds a new product.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `product` | `IProduct` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:254](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L254)
+
+___
+
+### addProductReview
+
+▸ **addProductReview**(`productName`, `productReview`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Adds a new review to chosen product.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `productName` | `string` |
+| `productReview` | `IReviews` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:383](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L383)
+
+___
+
+### addProductToObserved
+
+▸ **addProductToObserved**(`productId`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Adds product to observed by user, so they can more conveniently find it later.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `productId` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:496](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L496)
+
+___
+
+### changePassword
+
+▸ **changePassword**(`password`, `newPassword`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Changes user's current password to a new one.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `password` | `string` |
+| `newPassword` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:489](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L489)
+
+___
+
+### confirmRegistration
+
+▸ **confirmRegistration**(`token`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Confirms a newly registered user via token received on their email.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `token` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:468](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L468)
+
+___
+
+### deleteProduct
+
+▸ **deleteProduct**(`productName`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Delets a product via it's name.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `productName` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:390](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L390)
+
+___
+
+### getCurrentUser
+
+▸ **getCurrentUser**(): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Gets info about currently logged in user via it's ID taken from app's state.
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:397](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L397)
+
+___
+
+### getObservedProducts
+
+▸ **getObservedProducts**(): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Retrieves all observed products by user.
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:517](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L517)
+
+___
+
+### getProductByUrl
+
+▸ **getProductByUrl**(`url`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Gets product by it's URL - mostly useful for retrieving product from browser's address bar.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `url` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:337](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L337)
+
+___
+
+### getProductCategories
+
+▸ **getProductCategories**(): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Gets categories of all products.
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:353](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L353)
+
+___
+
+### getProducts
+
+▸ **getProducts**(`initialSearchParams`, `customSearchParamsSerialization?`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Gets products according to optional constraints like: name, price, pagination etc.
+
+#### Parameters
+
+| Name | Type | Default value |
+| :------ | :------ | :------ |
+| `initialSearchParams` | `Partial`<{ `name`: `string` ; `pagination`: [`TPagination`](#tpagination) ; `price`: [`number`, `number`] ; `productCategories`: `string` ; `productTechnicalSpecs`: `string` ; `sortBy`: `string` }\> | `undefined` |
+| `customSearchParamsSerialization` | `boolean` | `false` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:261](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L261)
+
+___
+
+### getProductsById
+
+▸ **getProductsById**(`idList`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `idList` | `any`[] |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:305](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L305)
+
+___
+
+### getProductsByName
+
+▸ **getProductsByName**(`name`, `pagination`, `getOnlyEssentialData?`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Gets products by a single name - mostly useful for search feature.
+
+#### Parameters
+
+| Name | Type | Default value |
+| :------ | :------ | :------ |
+| `name` | `string` | `undefined` |
+| `pagination` | [`TPagination`](#tpagination) | `undefined` |
+| `getOnlyEssentialData` | `boolean` | `true` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:324](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L324)
+
+___
+
+### getProductsByNames
+
+▸ **getProductsByNames**(`nameList`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Gets products by list of names - mostly useful for retrieving related products of a single one.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `nameList` | `string`[] |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:312](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L312)
+
+___
+
+### getProductsSpecifications
+
+▸ **getProductsSpecifications**(): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__EXCEPTION_ALREADY_HANDLED"``\> \| [`TProductTechnicalSpecs`](#tproducttechnicalspecs)\>
+
+Gets technical specifications of all products.
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__EXCEPTION_ALREADY_HANDLED"``\> \| [`TProductTechnicalSpecs`](#tproducttechnicalspecs)\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:360](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L360)
+
+___
+
+### getUserRoles
+
+▸ **getUserRoles**(): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Gets all user roles.
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:454](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L454)
+
+___
+
+### logOutUserFromSessions
+
+▸ **logOutUserFromSessions**(`preseveCurrentSession?`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Loggs out user from all sessions; current session can be preserved if `preseveCurrentSession` param is true.
+
+#### Parameters
+
+| Name | Type | Default value |
+| :------ | :------ | :------ |
+| `preseveCurrentSession` | `boolean` | `false` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:447](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L447)
+
+___
+
+### loginUser
+
+▸ **loginUser**(`loginCredentials`): `Promise`<[`TUserPublic`](#tuserpublic) \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Logs in user based on their login and password credentials.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `loginCredentials` | `Object` |
+| `loginCredentials.login` | `string` |
+| `loginCredentials.password` | `string` |
+
+#### Returns
+
+`Promise`<[`TUserPublic`](#tuserpublic) \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:417](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L417)
+
+___
+
+### logoutUser
+
+▸ **logoutUser**(): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Loggs out user from current session.
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:440](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L440)
+
+___
+
+### makeOrder
+
+▸ **makeOrder**(`orderDetails`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Starts the process of making a new purchase according to given order details.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `orderDetails` | [`IOrder`](#interfacesfeatures_httpservice_internal_iordermd) |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:410](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L410)
+
+___
+
+### modifyProduct
+
+▸ **modifyProduct**(`productName`, `productModifications`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Modifies product.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `productName` | `string` |
+| `productModifications` | `Partial`<`IProduct`\> |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:369](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L369)
+
+___
+
+### registerUser
+
+▸ **registerUser**(`registrationCredentials`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Registers a new user according to provided credentials.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `registrationCredentials` | [`TUserRegistrationCredentials`](#tuserregistrationcredentials) |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:461](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L461)
+
+___
+
+### removeAllProductsFromObserved
+
+▸ **removeAllProductsFromObserved**(): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Removes all products from observed by user.
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:510](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L510)
+
+___
+
+### removeProductFromObserved
+
+▸ **removeProductFromObserved**(`productId`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Removes product from observed by user.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `productId` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:503](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L503)
+
+___
+
+### resendConfirmRegistration
+
+▸ **resendConfirmRegistration**(`email`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Resends registration confirmation email.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `email` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:475](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L475)
+
+___
+
+### resendResetPassword
+
+▸ **resendResetPassword**(`email`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Resends (repeats) resetting user password via it's email.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `email` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:433](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L433)
+
+___
+
+### resetPassword
+
+▸ **resetPassword**(`email`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Resets user password via it's email.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `email` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:426](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L426)
+
+___
+
+### setNewPassword
+
+▸ **setNewPassword**(`newPassword`, `token`): `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+Sets a new password for user - mostly after reseting password.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `newPassword` | `string` |
+| `token` | `string` |
+
+#### Returns
+
+`Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:482](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L482)
+
+[fake-pev-shopping](#readmemd) / [features/storageService](#modulesfeatures_storageservicemd) / [](#modulesfeatures_storageservice_internal_md) / StorageService
+
+# Class: StorageService
+
+[features/storageService](#modulesfeatures_storageservicemd).[](#modulesfeatures_storageservice_internal_md).StorageService
+
+## Hierarchy
+
+- **`StorageService`**
+
+ ↳ [`UserCart`](#classesfeatures_storageservice_internal_usercartmd)
+
+ ↳ [`UserAccount`](#classesfeatures_storageservice_internal_useraccountmd)
+
+ ↳ [`UserAuthToken`](#classesfeatures_storageservice_internal_userauthtokenmd)
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new StorageService**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:18](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L18)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`value`, `checkIfShouldRemove`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `value` | [`TStorageValue`](#tstoragevalue) |
+| `checkIfShouldRemove` | () => `boolean` |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:26](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L26)
+
+[fake-pev-shopping](#readmemd) / [features/storageService](#modulesfeatures_storageservicemd) / [](#modulesfeatures_storageservice_internal_md) / UserAccount
+
+# Class: UserAccount
+
+[features/storageService](#modulesfeatures_storageservicemd).[](#modulesfeatures_storageservice_internal_md).UserAccount
+
+## Hierarchy
+
+- [`StorageService`](#classesfeatures_storageservice_internal_storageservicemd)
+
+ ↳ **`UserAccount`**
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new UserAccount**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Overrides
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[constructor](#constructor)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:70](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L70)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[key](#key)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[get](#get)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[remove](#remove)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`accountState`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `accountState` | [`TUserPublic`](#tuserpublic) |
+
+#### Returns
+
+`void`
+
+#### Overrides
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[update](#update)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:74](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L74)
+
+[fake-pev-shopping](#readmemd) / [features/storageService](#modulesfeatures_storageservicemd) / [](#modulesfeatures_storageservice_internal_md) / UserAuthToken
+
+# Class: UserAuthToken
+
+[features/storageService](#modulesfeatures_storageservicemd).[](#modulesfeatures_storageservice_internal_md).UserAuthToken
+
+## Hierarchy
+
+- [`StorageService`](#classesfeatures_storageservice_internal_storageservicemd)
+
+ ↳ **`UserAuthToken`**
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new UserAuthToken**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Overrides
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[constructor](#constructor)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:80](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L80)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[key](#key)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[get](#get)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[remove](#remove)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`authToken`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `authToken` | `string` |
+
+#### Returns
+
+`void`
+
+#### Overrides
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[update](#update)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:84](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L84)
+
+[fake-pev-shopping](#readmemd) / [features/storageService](#modulesfeatures_storageservicemd) / [](#modulesfeatures_storageservice_internal_md) / UserCart
+
+# Class: UserCart
+
+[features/storageService](#modulesfeatures_storageservicemd).[](#modulesfeatures_storageservice_internal_md).UserCart
+
+## Hierarchy
+
+- [`StorageService`](#classesfeatures_storageservice_internal_storageservicemd)
+
+ ↳ **`UserCart`**
+
+## Table of contents
+
+### Constructors
+
+- [constructor](#constructor)
+
+### Properties
+
+- [key](#key)
+
+### Methods
+
+- [get](#get)
+- [remove](#remove)
+- [update](#update)
+
+## Constructors
+
+### constructor
+
+• **new UserCart**(`key`)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `key` | `string` |
+
+#### Overrides
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[constructor](#constructor)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:60](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L60)
+
+## Properties
+
+### key
+
+• **key**: `string`
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[key](#key)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L16)
+
+## Methods
+
+### get
+
+▸ **get**(): `any`
+
+#### Returns
+
+`any`
+
+Already parsed (from JSON) stored value.
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[get](#get)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:42](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L42)
+
+___
+
+### remove
+
+▸ **remove**(): `void`
+
+Removes a values.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[remove](#remove)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:54](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L54)
+
+___
+
+### update
+
+▸ **update**(`cartState`): `void`
+
+Update regarding storage context by either setting given `value` or removing existing one,
+depending on result of calling `checkIfShouldRemove`.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `cartState` | [`IUserCart`](#interfacescomponents_pages__routes_internal_iusercartmd) |
+
+#### Returns
+
+`void`
+
+#### Overrides
+
+[StorageService](#classesfeatures_storageservice_internal_storageservicemd).[update](#update)
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:64](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L64)
+
+[fake-pev-shopping](#readmemd) / [components/pages/\_routes](#modulescomponents_pages__routesmd) / [](#modulescomponents_pages__routes_internal_md) / IUserCart
+
+# Interface: IUserCart
+
+[components/pages/_routes](#modulescomponents_pages__routesmd).[](#modulescomponents_pages__routes_internal_md).IUserCart
+
+## Table of contents
+
+### Properties
+
+- [products](#products)
+- [totalCount](#totalcount)
+- [totalPrice](#totalprice)
+
+## Properties
+
+### products
+
+• **products**: { `_id`: `string` ; `name`: `string` ; `price`: `number` }[]
+
+#### Defined in
+
+[commons/types.ts:53](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L53)
+
+___
+
+### totalCount
+
+• **totalCount**: `number`
+
+#### Defined in
+
+[commons/types.ts:58](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L58)
+
+___
+
+### totalPrice
+
+• **totalPrice**: `number`
+
+#### Defined in
+
+[commons/types.ts:59](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L59)
+
+[fake-pev-shopping](#readmemd) / [features/httpService](#modulesfeatures_httpservicemd) / [](#modulesfeatures_httpservice_internal_md) / ICustomResExt
+
+# Interface: ICustomResExt
+
+[features/httpService](#modulesfeatures_httpservicemd).[](#modulesfeatures_httpservice_internal_md).ICustomResExt
+
+## Table of contents
+
+### Properties
+
+- [\_\_ERROR\_TO\_HANDLE](#__error_to_handle)
+- [\_\_EXCEPTION\_ALREADY\_HANDLED](#__exception_already_handled)
+- [\_\_NO\_CONTENT](#__no_content)
+
+## Properties
+
+### \_\_ERROR\_TO\_HANDLE
+
+• **\_\_ERROR\_TO\_HANDLE**: `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"error"``\>
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:570](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L570)
+
+___
+
+### \_\_EXCEPTION\_ALREADY\_HANDLED
+
+• **\_\_EXCEPTION\_ALREADY\_HANDLED**: ``true``
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:571](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L571)
+
+___
+
+### \_\_NO\_CONTENT
+
+• **\_\_NO\_CONTENT**: ``true``
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:569](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L569)
+
+[fake-pev-shopping](#readmemd) / [features/httpService](#modulesfeatures_httpservicemd) / [](#modulesfeatures_httpservice_internal_md) / IEmbracedResponse
+
+# Interface: IEmbracedResponse
+
+[features/httpService](#modulesfeatures_httpservicemd).[](#modulesfeatures_httpservice_internal_md).IEmbracedResponse
+
+## Type parameters
+
+| Name | Type |
+| :------ | :------ |
+| `PayloadType` | `never` |
+
+## Table of contents
+
+### Properties
+
+- [authToken](#authtoken)
+- [error](#error)
+- [exception](#exception)
+- [message](#message)
+- [payload](#payload)
+
+## Properties
+
+### authToken
+
+• **authToken**: ``null`` \| `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:11](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L11)
+
+___
+
+### error
+
+• **error**: `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L14)
+
+___
+
+### exception
+
+• **exception**: `Error` \| { `message`: `string` ; `stack?`: `string` }
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:15](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L15)
+
+___
+
+### message
+
+• **message**: `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:13](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L13)
+
+___
+
+### payload
+
+• **payload**: `Record`<`string`, `unknown`\> \| `unknown`[] \| `PayloadType`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:12](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L12)
+
+[fake-pev-shopping](#readmemd) / [features/httpService](#modulesfeatures_httpservicemd) / [](#modulesfeatures_httpservice_internal_md) / IOrder
+
+# Interface: IOrder
+
+[features/httpService](#modulesfeatures_httpservicemd).[](#modulesfeatures_httpservice_internal_md).IOrder
+
+## Table of contents
+
+### Properties
+
+- [paymentType](#paymenttype)
+- [price](#price)
+- [products](#products)
+- [receiver](#receiver)
+- [shipmentType](#shipmenttype)
+
+## Properties
+
+### paymentType
+
+• **paymentType**: ``"Cash"`` \| ``"Card"`` \| ``"Transfer"`` \| ``"BLIK"``
+
+#### Defined in
+
+[commons/types.ts:73](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L73)
+
+___
+
+### price
+
+• **price**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `shipment` | `number` |
+| `total` | `number` |
+
+#### Defined in
+
+[commons/types.ts:75](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L75)
+
+___
+
+### products
+
+• **products**: { `_id`: `string` ; `name`: `string` ; `price`: `number` }[] & { `count`: `number` }[]
+
+#### Defined in
+
+[commons/types.ts:74](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L74)
+
+___
+
+### receiver
+
+• **receiver**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `address` | `string` |
+| `baseInfo` | { `email`: `string` ; `name`: `string` ; `phone`: `string` } |
+| `baseInfo.email` | `string` |
+| `baseInfo.name` | `string` |
+| `baseInfo.phone` | `string` |
+
+#### Defined in
+
+[commons/types.ts:63](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L63)
+
+___
+
+### shipmentType
+
+• **shipmentType**: ``"inPerson"`` \| ``"home"`` \| ``"parcelLocker"``
+
+#### Defined in
+
+[commons/types.ts:71](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L71)
+
+[fake-pev-shopping](#readmemd) / [components/pages/\_routes](#modulescomponents_pages__routesmd) /
+
+# Namespace:
+
+[components/pages/_routes](#modulescomponents_pages__routesmd).
+
+## Table of contents
+
+### Classes
+
+- [StoreService](#classescomponents_pages__routes_internal_storeservicemd)
+
+### Interfaces
+
+- [IUserCart](#interfacescomponents_pages__routes_internal_iusercartmd)
+
+### Type Aliases
+
+- [TUserCartProduct](#tusercartproduct)
+- [TUserPublic](#tuserpublic)
+
+## Type Aliases
+
+### TUserCartProduct
+
+Ƭ **TUserCartProduct**: [`IUserCart`](#interfacescomponents_pages__routes_internal_iusercartmd)[``"products"``][`number`] & { `count`: `number` }
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:17](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L17)
+
+___
+
+### TUserPublic
+
+Ƭ **TUserPublic**: `Pick`<`IUser`, ``"login"`` \| ``"email"`` \| ``"observedProductsIDs"``\> & { `_id`: `Schema.Types.ObjectId` ; `accountType`: `NonNullable`<`IUser`[``"accountType"``]\>[``"roleName"``] }
+
+#### Defined in
+
+[src/database/models/_user.ts:242](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L242)
+
+[fake-pev-shopping](#readmemd) / components/pages/\_routes
+
+# Module: components/pages/\_routes
+
+Encapsulates routing paths and methods (such as helpers and guards).
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulescomponents_pages__routes_internal_md)
+
+### Variables
+
+- [ROUTES](#routes)
+- [routeHelpers](#routehelpers)
+
+### Functions
+
+- [useRoutesGuards](#useroutesguards)
+
+## Variables
+
+### ROUTES
+
+• `Const` **ROUTES**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `ACCOUNT` | `string` |
+| `CONFIRM_REGISTRATION` | ``"/pages/confirm-registration"`` |
+| `LOG_IN` | ``"/pages/log-in"`` |
+| `NOT_AUTHORIZED` | ``"/pages/not-authorized"`` |
+| `NOT_FOUND` | ``"/pages/not-found"`` |
+| `NOT_LOGGED_IN` | ``"/pages/not-logged-in"`` |
+| `PAGES` | ``"/pages"`` |
+| `PRODUCTS` | `string` |
+| `PRODUCTS__ADD_NEW_PRODUCT` | \`${string}/add-new-product\` |
+| `PRODUCTS__COMPARE` | \`${string}/compare\` |
+| `PRODUCTS__ORDER` | \`${string}/order\` |
+| `PRODUCTS__PRODUCT` | \`${string}/:productName\` |
+| `REGISTER` | ``"/pages/register"`` |
+| `RESET_PASSWORD` | ``"/pages/reset-password"`` |
+| `ROOT` | ``"/"`` |
+| `SET_NEW_PASSWORD` | ``"/pages/set-new-password"`` |
+| ``get` **ACCOUNT__OBSERVED_PRODUCTS**(): `string`` | {} |
+| ``get` **ACCOUNT__ORDERS**(): `string`` | {} |
+| ``get` **ACCOUNT__SECURITY**(): `string`` | {} |
+| ``get` **ACCOUNT__USER_PROFILE**(): `string`` | {} |
+| ``get` **PRODUCTS__MODIFY_PRODUCT**(): `string`` | {} |
+
+#### Defined in
+
+[src/frontend/components/pages/_routes.ts:23](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/pages/_routes.ts#L23)
+
+___
+
+### routeHelpers
+
+• `Const` **routeHelpers**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `createModifyProductUrl` | (`productName`: `string`) => `string` |
+| `createProductsDashboardQueryUpdater` | (`currentQueryParams`: `ParsedQuery`<`string`\>, `pathname`: `string`, `history`: `History`<`unknown`\>) => (`updates`: ``null`` \| { `[key: string]`: `string` \| `number` \| `boolean`; }) => `void` |
+| `extractProductUrlFromPathname` | (`pathname`: `string`) => `string` |
+| `parseSearchParams` | (`search`: `string`) => `ParsedQuery`<`string` \| `number` \| `boolean`\> |
+| `stringifySearchParams` | (`payload`: `Record`<`string`, `unknown`\>) => `string` |
+
+#### Defined in
+
+[src/frontend/components/pages/_routes.ts:64](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/pages/_routes.ts#L64)
+
+## Functions
+
+### useRoutesGuards
+
+▸ **useRoutesGuards**(`storeService`): `Object`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `storeService` | [`StoreService`](#classescomponents_pages__routes_internal_storeservicemd) |
+
+#### Returns
+
+`Object`
+
+| Name | Type |
+| :------ | :------ |
+| `isClient` | () => ``null`` \| `boolean` |
+| `isGuest` | () => `boolean` |
+| `isSeller` | () => ``null`` \| `boolean` |
+| `isUser` | () => `boolean` |
+
+#### Defined in
+
+[src/frontend/components/pages/_routes.ts:99](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/pages/_routes.ts#L99)
+
+[fake-pev-shopping](#readmemd) / [components/utils/bodyObserver](#modulescomponents_utils_bodyobservermd) /
+
+# Namespace:
+
+[components/utils/bodyObserver](#modulescomponents_utils_bodyobservermd).
+
+## Table of contents
+
+### Type Aliases
+
+- [TSubscriptionCallback](#tsubscriptioncallback)
+
+## Type Aliases
+
+### TSubscriptionCallback
+
+Ƭ **TSubscriptionCallback**: `Object`
+
+#### Call signature
+
+▸ (`bodyStyle`): `void`
+
+##### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `bodyStyle` | `CSSStyleDeclaration` |
+
+##### Returns
+
+`void`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `subscriptionID` | `number` |
+
+#### Defined in
+
+[src/frontend/components/utils/bodyObserver.tsx:7](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/bodyObserver.tsx#L7)
+
+[fake-pev-shopping](#readmemd) / components/utils/bodyObserver
+
+# Module: components/utils/bodyObserver
+
+Handles HTML `` style changes, which affect position of components,
+such as `ScrollToTop` button and `ProductComparisonCandidates` bar.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulescomponents_utils_bodyobserver_internal_md)
+
+### Functions
+
+- [subscribeToBodyMutations](#subscribetobodymutations)
+- [unSubscribeFromBodyMutations](#unsubscribefrombodymutations)
+
+## Functions
+
+### subscribeToBodyMutations
+
+▸ **subscribeToBodyMutations**(`callback`): `number`
+
+Subscribes a provided `callback` to `` style mutations.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `callback` | [`TSubscriptionCallback`](#tsubscriptioncallback) |
+
+#### Returns
+
+`number`
+
+subscriptionID, which lets unsubscribing `callback` later.
+
+#### Defined in
+
+[src/frontend/components/utils/bodyObserver.tsx:26](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/bodyObserver.tsx#L26)
+
+___
+
+### unSubscribeFromBodyMutations
+
+▸ **unSubscribeFromBodyMutations**(`subscriptionID`): `void`
+
+Unsubscribes previously subscribed `callback` (via it's ID) from `` style mutations.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `subscriptionID` | `number` |
+
+#### Returns
+
+`void`
+
+#### Defined in
+
+[src/frontend/components/utils/bodyObserver.tsx:36](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/bodyObserver.tsx#L36)
+
+[fake-pev-shopping](#readmemd) / components/utils/flexibleList
+
+# Module: components/utils/flexibleList
+
+Flexible list component, which allows adding, editing and deleting it's items in a customizable way.
+
+## Table of contents
+
+### Functions
+
+- [FlexibleList](#flexiblelist)
+
+## Functions
+
+### FlexibleList
+
+▸ **FlexibleList**(`__namedParameters`): `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+
+#### Returns
+
+`Element`
+
+#### Defined in
+
+[src/frontend/components/utils/flexibleList.jsx:72](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/flexibleList.jsx#L72)
+
+[fake-pev-shopping](#readmemd) / components/utils/pagination
+
+# Module: components/utils/pagination
+
+## Table of contents
+
+### Functions
+
+- [Pagination](#pagination)
+
+## Functions
+
+### Pagination
+
+▸ **Pagination**(`props`): `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `props` | `any` |
+
+#### Returns
+
+`Element`
+
+#### Defined in
+
+[src/frontend/components/utils/pagination.jsx:20](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pagination.jsx#L20)
+
+[fake-pev-shopping](#readmemd) / components/utils/pevElements
+
+# Module: components/utils/pevElements
+
+Facade over commonly used MUI and native HTML elements.
+
+## Table of contents
+
+### Variables
+
+- [PEVButton](#pevbutton)
+- [PEVCheckbox](#pevcheckbox)
+- [PEVFieldset](#pevfieldset)
+- [PEVForm](#pevform)
+- [PEVHeading](#pevheading)
+- [PEVIconButton](#peviconbutton)
+- [PEVLegend](#pevlegend)
+- [PEVLink](#pevlink)
+- [PEVParagraph](#pevparagraph)
+- [PEVRadio](#pevradio)
+- [PEVTabs](#pevtabs)
+
+### Functions
+
+- [PEVFormFieldError](#pevformfielderror)
+- [PEVTextField](#pevtextfield)
+
+## Variables
+
+### PEVButton
+
+• `Const` **PEVButton**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:44](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L44)
+
+___
+
+### PEVCheckbox
+
+• `Const` **PEVCheckbox**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:177](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L177)
+
+___
+
+### PEVFieldset
+
+• `Const` **PEVFieldset**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:86](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L86)
+
+___
+
+### PEVForm
+
+• `Const` **PEVForm**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:185](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L185)
+
+___
+
+### PEVHeading
+
+• `Const` **PEVHeading**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:220](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L220)
+
+___
+
+### PEVIconButton
+
+• `Const` **PEVIconButton**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:62](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L62)
+
+___
+
+### PEVLegend
+
+• `Const` **PEVLegend**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:94](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L94)
+
+___
+
+### PEVLink
+
+• `Const` **PEVLink**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:78](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L78)
+
+___
+
+### PEVParagraph
+
+• `Const` **PEVParagraph**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:234](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L234)
+
+___
+
+### PEVRadio
+
+• `Const` **PEVRadio**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:181](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L181)
+
+___
+
+### PEVTabs
+
+• `Const` **PEVTabs**: `ForwardRefExoticComponent`<`RefAttributes`<`any`\>\>
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:282](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L282)
+
+## Functions
+
+### PEVFormFieldError
+
+▸ **PEVFormFieldError**(`__namedParameters`): `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+
+#### Returns
+
+`Element`
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:216](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L216)
+
+___
+
+### PEVTextField
+
+▸ **PEVTextField**(`__namedParameters`): `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+
+#### Returns
+
+`Element`
+
+#### Defined in
+
+[src/frontend/components/utils/pevElements.jsx:102](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/pevElements.jsx#L102)
+
+[fake-pev-shopping](#readmemd) / components/utils/popup
+
+# Module: components/utils/popup
+
+## Table of contents
+
+### Variables
+
+- [GenericErrorPopup](#genericerrorpopup)
+- [POPUP\_TYPES](#popup_types)
+
+### Functions
+
+- [Popup](#popup)
+- [getClosePopupBtn](#getclosepopupbtn)
+
+## Variables
+
+### GenericErrorPopup
+
+• `Const` **GenericErrorPopup**: `NamedExoticComponent`<`object`\>
+
+Generic error popup component is hooked on [HttpService](#classesfeatures_httpservice_internal_httpservicemd) to present user any errors in more friendly way.
+
+#### Defined in
+
+[src/frontend/components/utils/popup.jsx:57](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/popup.jsx#L57)
+
+___
+
+### POPUP\_TYPES
+
+• `Const` **POPUP\_TYPES**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `FAILURE` | `string` |
+| `NEUTRAL` | `string` |
+| `SUCCESS` | `string` |
+
+#### Defined in
+
+[src/frontend/components/utils/popup.jsx:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/popup.jsx#L16)
+
+## Functions
+
+### Popup
+
+▸ **Popup**(`props`): ``null`` \| `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `props` | `any` |
+
+#### Returns
+
+``null`` \| `Element`
+
+#### Defined in
+
+[src/frontend/components/utils/popup.jsx:92](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/popup.jsx#L92)
+
+___
+
+### getClosePopupBtn
+
+▸ **getClosePopupBtn**(`setPopupData`): `Object`
+
+Factory for popup's default closing button.
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `setPopupData` | `any` |
+
+#### Returns
+
+`Object`
+
+| Name | Type |
+| :------ | :------ |
+| `dataCy` | `string` |
+| `onClick` | () => `any` |
+| `text` | `string` |
+
+#### Defined in
+
+[src/frontend/components/utils/popup.jsx:25](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/popup.jsx#L25)
+
+[fake-pev-shopping](#readmemd) / components/utils/ratingWidget
+
+# Module: components/utils/ratingWidget
+
+## Table of contents
+
+### Functions
+
+- [RatingWidget](#ratingwidget)
+
+## Functions
+
+### RatingWidget
+
+▸ **RatingWidget**(`__namedParameters`): `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+
+#### Returns
+
+`Element`
+
+#### Defined in
+
+[src/frontend/components/utils/ratingWidget.jsx:17](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/ratingWidget.jsx#L17)
+
+[fake-pev-shopping](#readmemd) / components/utils/scroller
+
+# Module: components/utils/scroller
+
+## Table of contents
+
+### Functions
+
+- [Scroller](#scroller)
+
+## Functions
+
+### Scroller
+
+▸ **Scroller**(`__namedParameters`): `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `Object` |
+
+#### Returns
+
+`Element`
+
+#### Defined in
+
+[src/frontend/components/utils/scroller.jsx:94](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/components/utils/scroller.jsx#L94)
+
+[fake-pev-shopping](#readmemd) / contexts/rwd-layout
+
+# Module: contexts/rwd-layout
+
+Observes DOM viewport changes and emits information about the currently established one.
+
+## Table of contents
+
+### Functions
+
+- [RWDLayoutProvider](#rwdlayoutprovider)
+- [useRWDLayout](#userwdlayout)
+
+## Functions
+
+### RWDLayoutProvider
+
+▸ **RWDLayoutProvider**(`__namedParameters`): `Element`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `__namedParameters` | `PropsWithChildren`<`Record`<`string`, `unknown`\>\> |
+
+#### Returns
+
+`Element`
+
+#### Defined in
+
+[src/frontend/contexts/rwd-layout.tsx:79](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/contexts/rwd-layout.tsx#L79)
+
+___
+
+### useRWDLayout
+
+▸ **useRWDLayout**(): `Object`
+
+#### Returns
+
+`Object`
+
+#### Defined in
+
+[src/frontend/contexts/rwd-layout.tsx:83](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/contexts/rwd-layout.tsx#L83)
+
+[fake-pev-shopping](#readmemd) / [features/httpService](#modulesfeatures_httpservicemd) /
+
+# Namespace:
+
+[features/httpService](#modulesfeatures_httpservicemd).
+
+## Table of contents
+
+### Classes
+
+- [Ajax](#classesfeatures_httpservice_internal_ajaxmd)
+- [HttpService](#classesfeatures_httpservice_internal_httpservicemd)
+
+### Interfaces
+
+- [ICustomResExt](#interfacesfeatures_httpservice_internal_icustomresextmd)
+- [IEmbracedResponse](#interfacesfeatures_httpservice_internal_iembracedresponsemd)
+- [IOrder](#interfacesfeatures_httpservice_internal_iordermd)
+
+### Type Aliases
+
+- [TIntermediateSpecsValues](#tintermediatespecsvalues)
+- [TOutputSpecs](#toutputspecs)
+- [TPagination](#tpagination)
+- [TProductTechnicalSpecs](#tproducttechnicalspecs)
+- [TSubCallback](#tsubcallback)
+- [TUserRegistrationCredentials](#tuserregistrationcredentials)
+
+## Type Aliases
+
+### TIntermediateSpecsValues
+
+Ƭ **TIntermediateSpecsValues**: (`string` \| `number`)[] \| `Record`<`string`, `number`[]\>
+
+#### Defined in
+
+[src/middleware/helpers/api-products-specs-mapper.ts:4](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/api-products-specs-mapper.ts#L4)
+
+___
+
+### TOutputSpecs
+
+Ƭ **TOutputSpecs**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `defaultUnit` | `string` |
+| `name` | `string` |
+| `values` | [`TIntermediateSpecsValues`](#tintermediatespecsvalues) |
+
+#### Defined in
+
+[src/middleware/helpers/api-products-specs-mapper.ts:8](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/api-products-specs-mapper.ts#L8)
+
+___
+
+### TPagination
+
+Ƭ **TPagination**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `pageNumber` | `number` |
+| `productsPerPage` | `number` |
+
+#### Defined in
+
+[commons/types.ts:81](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L81)
+
+___
+
+### TProductTechnicalSpecs
+
+Ƭ **TProductTechnicalSpecs**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `categoryToSpecs` | `Record`<`string`, `string`[]\> |
+| `specs` | [`TOutputSpecs`](#toutputspecs)[] |
+
+#### Defined in
+
+[src/middleware/helpers/api-products-specs-mapper.ts:13](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/api-products-specs-mapper.ts#L13)
+
+___
+
+### TSubCallback
+
+Ƭ **TSubCallback**: (...`args`: `unknown`[]) => `unknown`
+
+#### Type declaration
+
+▸ (...`args`): `unknown`
+
+##### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `...args` | `unknown`[] |
+
+##### Returns
+
+`unknown`
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:531](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L531)
+
+___
+
+### TUserRegistrationCredentials
+
+Ƭ **TUserRegistrationCredentials**: `Pick`<`IUser`, ``"login"`` \| ``"password"`` \| ``"email"``\> & { `repeatedPassword`: `IUser`[``"password"``] }
+
+#### Defined in
+
+[src/database/models/_user.ts:285](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L285)
+
+[fake-pev-shopping](#readmemd) / features/httpService
+
+# Module: features/httpService
+
+Handles HTTP communication between frontend and backend.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesfeatures_httpservice_internal_md)
+
+### Variables
+
+- [CUSTOM\_RES\_EXT\_DICT](#custom_res_ext_dict)
+- [httpService](#httpservice)
+- [httpServiceSubscriber](#httpservicesubscriber)
+
+## Variables
+
+### CUSTOM\_RES\_EXT\_DICT
+
+• `Const` **CUSTOM\_RES\_EXT\_DICT**: `Readonly`<{ `__ERROR_TO_HANDLE`: ``"__ERROR_TO_HANDLE"`` = '\_\_ERROR\_TO\_HANDLE'; `__EXCEPTION_ALREADY_HANDLED`: ``"__EXCEPTION_ALREADY_HANDLED"`` = '\_\_EXCEPTION\_ALREADY\_HANDLED'; `__NO_CONTENT`: ``"__NO_CONTENT"`` = '\_\_NO\_CONTENT' }\>
+
+Recognize HTTP responses kinds.
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:562](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L562)
+
+___
+
+### httpService
+
+• **httpService**: [`HttpService`](#classesfeatures_httpservice_internal_httpservicemd)
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:576](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L576)
+
+___
+
+### httpServiceSubscriber
+
+• `Const` **httpServiceSubscriber**: `Object`
+
+Keeps track of [HttpService](#classesfeatures_httpservice_internal_httpservicemd) subscribers, which want to externally hook into any request
+that returns certain status.
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `SUBSCRIPTION_TYPE` | `Readonly`<{ `[k: string]`: `T`; }\> |
+| `callSubscribers` | (`type`: `string`, `value`: `unknown`) => `unknown` |
+| `subscribe` | (`type`: `string`, `callback`: [`TSubCallback`](#tsubcallback)) => `void` |
+| `unSubscribe` | (`type`: `string`) => `void` |
+
+#### Defined in
+
+[src/frontend/features/httpService.ts:526](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/httpService.ts#L526)
+
+[fake-pev-shopping](#readmemd) / [features/storageService](#modulesfeatures_storageservicemd) /
+
+# Namespace:
+
+[features/storageService](#modulesfeatures_storageservicemd).
+
+## Table of contents
+
+### Classes
+
+- [StorageService](#classesfeatures_storageservice_internal_storageservicemd)
+- [UserAccount](#classesfeatures_storageservice_internal_useraccountmd)
+- [UserAuthToken](#classesfeatures_storageservice_internal_userauthtokenmd)
+- [UserCart](#classesfeatures_storageservice_internal_usercartmd)
+
+### Type Aliases
+
+- [TStorageValue](#tstoragevalue)
+
+## Type Aliases
+
+### TStorageValue
+
+Ƭ **TStorageValue**: [`IUserCart`](#interfacescomponents_pages__routes_internal_iusercartmd) \| [`TUserPublic`](#tuserpublic) \| `NonNullable`<`IUser`[``"tokens"``][``"auth"``]\>[`number`] \| ``null``
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:9](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L9)
+
+[fake-pev-shopping](#readmemd) / features/storageService
+
+# Module: features/storageService
+
+Handles reading and manipulating browser's LocalStorage data.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesfeatures_storageservice_internal_md)
+
+### Variables
+
+- [storageService](#storageservice)
+
+## Variables
+
+### storageService
+
+• `Const` **storageService**: `Object`
+
+Manipulating storage data API for various contexts, such as `UserCart` or `UserAccount`.
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `userAccount` | [`UserAccount`](#classesfeatures_storageservice_internal_useraccountmd) |
+| `userAuthToken` | [`UserAuthToken`](#classesfeatures_storageservice_internal_userauthtokenmd) |
+| `userCart` | [`UserCart`](#classesfeatures_storageservice_internal_usercartmd) |
+
+#### Defined in
+
+[src/frontend/features/storageService.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storageService.ts#L14)
+
+[fake-pev-shopping](#readmemd) / features/storeService
+
+# Module: features/storeService
+
+## Table of contents
+
+### Type Aliases
+
+- [TStoreService](#tstoreservice)
+
+### Variables
+
+- [storeService](#storeservice)
+
+## Type Aliases
+
+### TStoreService
+
+Ƭ **TStoreService**: typeof [`storeService`](#storeservice)
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:177](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L177)
+
+## Variables
+
+### storeService
+
+• `Const` **storeService**: [`StoreService`](#classescomponents_pages__routes_internal_storeservicemd)
+
+#### Defined in
+
+[src/frontend/features/storeService.ts:169](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/storeService.ts#L169)
+
+[fake-pev-shopping](#readmemd) / features/userSessionService
+
+# Module: features/userSessionService
+
+## Table of contents
+
+### Variables
+
+- [userSessionService](#usersessionservice)
+
+## Variables
+
+### userSessionService
+
+• `Const` **userSessionService**: `Object`
+
+#### Type declaration
+
+| Name | Type |
+| :------ | :------ |
+| `logIn` | (`logInCredentials`: `Pick`<`IUser`, ``"login"`` \| ``"password"``\>) => `Promise`<[`TUserPublic`](#tuserpublic) \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__EXCEPTION_ALREADY_HANDLED"``\>\> |
+| `logOut` | () => `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\> |
+| `logOutFromMultipleSessions` | (`shouldPreserveCurrentSession`: `boolean`) => `Promise`<`Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__NO_CONTENT"``\> \| `Pick`<[`IEmbracedResponse`](#interfacesfeatures_httpservice_internal_iembracedresponsemd)<`never`\>, ``"authToken"`` \| ``"payload"`` \| ``"message"``\> \| `Pick`<[`ICustomResExt`](#interfacesfeatures_httpservice_internal_icustomresextmd), ``"__ERROR_TO_HANDLE"`` \| ``"__EXCEPTION_ALREADY_HANDLED"``\>\> |
+| `restoreSession` | () => `void` |
+
+#### Defined in
+
+[src/frontend/features/userSessionService.ts:12](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/frontend/features/userSessionService.ts#L12)
diff --git a/api-docs/middleware.md b/api-docs/middleware.md
new file mode 100644
index 00000000..8b1001d6
--- /dev/null
+++ b/api-docs/middleware.md
@@ -0,0 +1,1464 @@
+fake-pev-shopping
+
+# fake-pev-shopping
+
+## Table of contents
+
+### Modules
+
+- [features/auth](#modulesfeatures_authmd)
+- [helpers/mailer](#moduleshelpers_mailermd)
+- [helpers/middleware-error-handler](#moduleshelpers_middleware_error_handlermd)
+- [helpers/middleware-response-wrapper](#moduleshelpers_middleware_response_wrappermd)
+- [routes/api-config](#modulesroutes_api_configmd)
+- [routes/api-orders](#modulesroutes_api_ordersmd)
+- [routes/api-product-categories](#modulesroutes_api_product_categoriesmd)
+- [routes/api-products](#modulesroutes_api_productsmd)
+- [routes/api-user-roles](#modulesroutes_api_user_rolesmd)
+- [routes/api-users](#modulesroutes_api_usersmd)
+
+[fake-pev-shopping](#readmemd) / [helpers/middleware-response-wrapper](#moduleshelpers_middleware_response_wrappermd) / IEmbracedResponse
+
+# Interface: IEmbracedResponse
+
+[helpers/middleware-response-wrapper](#moduleshelpers_middleware_response_wrappermd).IEmbracedResponse
+
+## Type parameters
+
+| Name | Type |
+| :------ | :------ |
+| `PayloadType` | `never` |
+
+## Table of contents
+
+### Properties
+
+- [authToken](#authtoken)
+- [error](#error)
+- [exception](#exception)
+- [message](#message)
+- [payload](#payload)
+
+## Properties
+
+### authToken
+
+• **authToken**: ``null`` \| `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:11](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L11)
+
+___
+
+### error
+
+• **error**: `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L14)
+
+___
+
+### exception
+
+• **exception**: `Error` \| { `message`: `string` ; `stack?`: `string` }
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:15](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L15)
+
+___
+
+### message
+
+• **message**: `string`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:13](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L13)
+
+___
+
+### payload
+
+• **payload**: `PayloadType` \| `unknown`[] \| `Record`<`string`, `unknown`\>
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:12](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L12)
+
+[fake-pev-shopping](#readmemd) / [features/auth](#modulesfeatures_authmd) /
+
+# Namespace:
+
+[features/auth](#modulesfeatures_authmd).
+
+[fake-pev-shopping](#readmemd) / features/auth
+
+# Module: features/auth
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesfeatures_auth_internal_md)
+
+### Functions
+
+- [authMiddlewareFn](#authmiddlewarefn)
+- [authToPayU](#authtopayu)
+- [comparePasswords](#comparepasswords)
+- [getToken](#gettoken)
+- [hashPassword](#hashpassword)
+- [userRoleMiddlewareFn](#userrolemiddlewarefn)
+- [verifyToken](#verifytoken)
+
+## Functions
+
+### authMiddlewareFn
+
+▸ **authMiddlewareFn**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/features/auth.ts:38](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/features/auth.ts#L38)
+
+___
+
+### authToPayU
+
+▸ **authToPayU**(): `Promise`<`string` \| `Error`\>
+
+#### Returns
+
+`Promise`<`string` \| `Error`\>
+
+#### Defined in
+
+[src/middleware/features/auth.ts:96](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/features/auth.ts#L96)
+
+___
+
+### comparePasswords
+
+▸ **comparePasswords**(`password`, `passwordPattern`): `Promise`<`boolean`\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `password` | `string` |
+| `passwordPattern` | `string` |
+
+#### Returns
+
+`Promise`<`boolean`\>
+
+#### Defined in
+
+[src/middleware/features/auth.ts:22](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/features/auth.ts#L22)
+
+___
+
+### getToken
+
+▸ **getToken**(`payloadObj`): `string`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `payloadObj` | `TToken` |
+
+#### Returns
+
+`string`
+
+#### Defined in
+
+[src/middleware/features/auth.ts:30](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/features/auth.ts#L30)
+
+___
+
+### hashPassword
+
+▸ **hashPassword**(`password`): `Promise`<`string`\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `password` | `string` |
+
+#### Returns
+
+`Promise`<`string`\>
+
+#### Defined in
+
+[src/middleware/features/auth.ts:26](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/features/auth.ts#L26)
+
+___
+
+### userRoleMiddlewareFn
+
+▸ **userRoleMiddlewareFn**(`roleName`): (`req`: `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\>, `res`: `Response`<`any`, `Record`<`string`, `any`\>\>, `next`: `NextFunction`) => `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `roleName` | ``"client"`` \| ``"seller"`` |
+
+#### Returns
+
+`fn`
+
+▸ (`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+##### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+##### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/features/auth.ts:80](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/features/auth.ts#L80)
+
+___
+
+### verifyToken
+
+▸ **verifyToken**(`token`): `TToken`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `token` | `string` |
+
+#### Returns
+
+`TToken`
+
+#### Defined in
+
+[src/middleware/features/auth.ts:34](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/features/auth.ts#L34)
+
+[fake-pev-shopping](#readmemd) / helpers/mailer
+
+# Module: helpers/mailer
+
+## Table of contents
+
+### Variables
+
+- [EMAIL\_TYPES](#email_types)
+
+### Functions
+
+- [sendMail](#sendmail)
+
+## Variables
+
+### EMAIL\_TYPES
+
+• `Const` **EMAIL\_TYPES**: `Record`<``"ACTIVATION"`` \| ``"RESET_PASSWORD"``, ``"ACTIVATION"`` \| ``"RESET_PASSWORD"``\>
+
+#### Defined in
+
+[src/middleware/helpers/mailer.ts:51](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/mailer.ts#L51)
+
+## Functions
+
+### sendMail
+
+▸ **sendMail**(`receiver`, `emailType`, `link`): `Promise`<`SendmailTransport.SentMessageInfo`\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `receiver` | `string` |
+| `emailType` | ``"ACTIVATION"`` \| ``"RESET_PASSWORD"`` |
+| `link` | `string` |
+
+#### Returns
+
+`Promise`<`SendmailTransport.SentMessageInfo`\>
+
+#### Defined in
+
+[src/middleware/helpers/mailer.ts:55](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/mailer.ts#L55)
+
+[fake-pev-shopping](#readmemd) / [helpers/middleware-error-handler](#moduleshelpers_middleware_error_handlermd) /
+
+# Namespace:
+
+[helpers/middleware-error-handler](#moduleshelpers_middleware_error_handlermd).
+
+## Table of contents
+
+### Type Aliases
+
+- [TMiddlewareErrorHandler](#tmiddlewareerrorhandler)
+
+## Type Aliases
+
+### TMiddlewareErrorHandler
+
+Ƭ **TMiddlewareErrorHandler**: (`error`: `Error`, `req`: `Request`, `res`: `Response`) => `Pick`<`Response`, ``"json"``\>
+
+#### Type declaration
+
+▸ (`error`, `req`, `res`): `Pick`<`Response`, ``"json"``\>
+
+##### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `error` | `Error` |
+| `req` | `Request` |
+| `res` | `Response` |
+
+##### Returns
+
+`Pick`<`Response`, ``"json"``\>
+
+#### Defined in
+
+[src/middleware/helpers/middleware-error-handler.ts:10](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-error-handler.ts#L10)
+
+[fake-pev-shopping](#readmemd) / helpers/middleware-error-handler
+
+# Module: helpers/middleware-error-handler
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#moduleshelpers_middleware_error_handler_internal_md)
+
+### Functions
+
+- [getMiddlewareErrorHandler](#getmiddlewareerrorhandler)
+
+## Functions
+
+### getMiddlewareErrorHandler
+
+▸ **getMiddlewareErrorHandler**(`logger`): [`TMiddlewareErrorHandler`](#tmiddlewareerrorhandler)
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `logger` | `Logger` |
+
+#### Returns
+
+[`TMiddlewareErrorHandler`](#tmiddlewareerrorhandler)
+
+#### Defined in
+
+[src/middleware/helpers/middleware-error-handler.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-error-handler.ts#L14)
+
+[fake-pev-shopping](#readmemd) / [helpers/middleware-response-wrapper](#moduleshelpers_middleware_response_wrappermd) /
+
+# Namespace:
+
+[helpers/middleware-response-wrapper](#moduleshelpers_middleware_response_wrappermd).
+
+## Table of contents
+
+### Enumeration Members
+
+- [NOT\_FOUND](#not_found)
+- [NO\_CONTENT](#no_content)
+
+### Variables
+
+- [GROUPED\_HTTP\_STATUS\_CODES](#grouped_http_status_codes)
+
+## Enumeration Members
+
+### NOT\_FOUND
+
+• **NOT\_FOUND**: ``404``
+
+#### Defined in
+
+[commons/types.ts:45](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L45)
+
+___
+
+### NO\_CONTENT
+
+• **NO\_CONTENT**: ``204``
+
+#### Defined in
+
+[commons/types.ts:39](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/commons/types.ts#L39)
+
+## Variables
+
+### GROUPED\_HTTP\_STATUS\_CODES
+
+• `Const` **GROUPED\_HTTP\_STATUS\_CODES**: `Readonly`<{ `CLIENT_ERROR`: { `400`: ``400`` = 400; `401`: ``401`` = 401; `403`: ``403`` = 403; `404`: ``404`` = 404; `409`: ``409`` = 409 } ; `SERVER_ERROR`: { `500`: ``500`` = 500; `503`: ``503`` = 503; `511`: ``511`` = 511 } ; `SUCCESSFUL`: { `200`: ``200`` = 200; `201`: ``201`` = 201; `204`: ``204`` = 204 } }\>
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:19](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L19)
+
+[fake-pev-shopping](#readmemd) / helpers/middleware-response-wrapper
+
+# Module: helpers/middleware-response-wrapper
+
+Custom wrapper to secure consistent usage of a few [`Express#res`](https://expressjs.com/en/4x/api.html#res) methods.
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#moduleshelpers_middleware_response_wrapper_internal_md)
+
+### Interfaces
+
+- [IEmbracedResponse](#interfaceshelpers_middleware_response_wrapperiembracedresponsemd)
+
+### Type Aliases
+
+- [TClientErrorHTTPStatusCodesToData](#tclienterrorhttpstatuscodestodata)
+- [TServerErrorHTTPStatusCodesToData](#tservererrorhttpstatuscodestodata)
+- [TSuccessfulHTTPStatusCodesToData](#tsuccessfulhttpstatuscodestodata)
+- [TypeOfHTTPStatusCodes](#typeofhttpstatuscodes)
+
+### Functions
+
+- [wrapRes](#wrapres)
+
+## Type Aliases
+
+### TClientErrorHTTPStatusCodesToData
+
+Ƭ **TClientErrorHTTPStatusCodesToData**: { [ClientErrorStatus in keyof TypeOfHTTPStatusCodes["CLIENT\_ERROR"]]: Extract }
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:62](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L62)
+
+___
+
+### TServerErrorHTTPStatusCodesToData
+
+Ƭ **TServerErrorHTTPStatusCodesToData**: { [ServerErrorStatus in keyof TypeOfHTTPStatusCodes["SERVER\_ERROR"]]: Extract }
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:65](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L65)
+
+___
+
+### TSuccessfulHTTPStatusCodesToData
+
+Ƭ **TSuccessfulHTTPStatusCodesToData**: { [SuccessfulStatus in keyof TypeOfHTTPStatusCodes["SUCCESSFUL"]]: Extract }
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:56](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L56)
+
+___
+
+### TypeOfHTTPStatusCodes
+
+Ƭ **TypeOfHTTPStatusCodes**: typeof [`GROUPED_HTTP_STATUS_CODES`](#grouped_http_status_codes)
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:39](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L39)
+
+## Functions
+
+### wrapRes
+
+▸ **wrapRes**(`res`, `status`): `Response`
+
+It asserts that used `HTTP_STATUS_CODE` is adequate to provided optional payload shape (regarding it's key/label).
+
+**`example`** Without payload
+```ts
+wrapRes(res, HTTP_STATUS_CODE.NO_CONTENT);
+```
+
+**`example`** With payload
+```ts
+wrapRes(res, HTTP_STATUS_CODE.OK, { payload: someResourceValue });
+wrapRes(res, HTTP_STATUS_CODE.CREATED, { message: 'Resource created!' });
+wrapRes(res, HTTP_STATUS_CODE.NOT_FOUND, { error: 'Resource not found!' });
+```
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `status` | [`NO_CONTENT`](#no_content) \| [`NOT_FOUND`](#not_found) |
+
+#### Returns
+
+`Response`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:83](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L83)
+
+▸ **wrapRes**<`Payload`, `Status`, `DataKey`\>(`res`, `status`, `data`): `Response`
+
+It asserts that used `HTTP_STATUS_CODE` is adequate to provided optional payload shape (regarding it's key/label).
+
+**`example`** Without payload
+```ts
+wrapRes(res, HTTP_STATUS_CODE.NO_CONTENT);
+```
+
+**`example`** With payload
+```ts
+wrapRes(res, HTTP_STATUS_CODE.OK, { payload: someResourceValue });
+wrapRes(res, HTTP_STATUS_CODE.CREATED, { message: 'Resource created!' });
+wrapRes(res, HTTP_STATUS_CODE.NOT_FOUND, { error: 'Resource not found!' });
+```
+
+#### Type parameters
+
+| Name | Type |
+| :------ | :------ |
+| `Payload` | `Payload` |
+| `Status` | extends ``200`` \| ``201`` \| ``400`` \| ``401`` \| ``403`` \| ``404`` \| ``409`` \| ``500`` \| ``503`` \| ``511`` |
+| `DataKey` | extends ``"error"`` \| ``"authToken"`` \| ``"payload"`` \| ``"message"`` \| ``"exception"`` |
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `status` | `Status` |
+| `data` | `Record`<`DataKey`, [`IEmbracedResponse`](#interfaceshelpers_middleware_response_wrapperiembracedresponsemd)<`never`\>[`DataKey`]\> |
+
+#### Returns
+
+`Response`
+
+#### Defined in
+
+[src/middleware/helpers/middleware-response-wrapper.ts:87](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/helpers/middleware-response-wrapper.ts#L87)
+
+[fake-pev-shopping](#readmemd) / [routes/api-config](#modulesroutes_api_configmd) /
+
+# Namespace:
+
+[routes/api-config](#modulesroutes_api_configmd).
+
+## Table of contents
+
+### Functions
+
+- [populateDB](#populatedb)
+
+## Functions
+
+### populateDB
+
+▸ **populateDB**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-config.ts:22](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-config.ts#L22)
+
+[fake-pev-shopping](#readmemd) / routes/api-config
+
+# Module: routes/api-config
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesroutes_api_config_internal_md)
+
+### Variables
+
+- [router](#router)
+
+## Variables
+
+### router
+
+• `Const` **router**: `Router` & `Partial`<{ `_populateDB`: typeof [`populateDB`](#populatedb) }\>
+
+#### Defined in
+
+[src/middleware/routes/api-config.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-config.ts#L14)
+
+[fake-pev-shopping](#readmemd) / [routes/api-orders](#modulesroutes_api_ordersmd) /
+
+# Namespace:
+
+[routes/api-orders](#modulesroutes_api_ordersmd).
+
+## Table of contents
+
+### Functions
+
+- [handleOrderPreflight](#handleorderpreflight)
+- [makeOrder](#makeorder)
+
+## Functions
+
+### handleOrderPreflight
+
+▸ **handleOrderPreflight**(`req`, `res`): `Response`<`any`, `Record`<`string`, `any`\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+
+#### Returns
+
+`Response`<`any`, `Record`<`string`, `any`\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-orders.ts:36](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-orders.ts#L36)
+
+___
+
+### makeOrder
+
+▸ **makeOrder**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-orders.ts:45](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-orders.ts#L45)
+
+[fake-pev-shopping](#readmemd) / routes/api-orders
+
+# Module: routes/api-orders
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesroutes_api_orders_internal_md)
+
+### Variables
+
+- [router](#router)
+
+## Variables
+
+### router
+
+• `Const` **router**: `Router` & `Partial`<{ `_handleOrderPreflight`: typeof [`handleOrderPreflight`](#handleorderpreflight) ; `_makeOrder`: typeof [`makeOrder`](#makeorder) }\>
+
+#### Defined in
+
+[src/middleware/routes/api-orders.ts:17](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-orders.ts#L17)
+
+[fake-pev-shopping](#readmemd) / routes/api-product-categories
+
+# Module: routes/api-product-categories
+
+## Table of contents
+
+### Variables
+
+- [router](#router)
+
+## Variables
+
+### router
+
+• `Const` **router**: `Router`
+
+#### Defined in
+
+[src/middleware/routes/api-product-categories.ts:14](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-product-categories.ts#L14)
+
+[fake-pev-shopping](#readmemd) / [routes/api-products](#modulesroutes_api_productsmd) / [](#modulesroutes_api_products_internal_md) / addReview
+
+# Namespace: addReview
+
+[routes/api-products](#modulesroutes_api_productsmd).[](#modulesroutes_api_products_internal_md).addReview
+
+## Table of contents
+
+### Functions
+
+- [isIntOrDecimalHalf](#isintordecimalhalf)
+- [isNumber](#isnumber)
+
+## Functions
+
+### isIntOrDecimalHalf
+
+▸ **isIntOrDecimalHalf**(`value`): `boolean`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `value` | `number` |
+
+#### Returns
+
+`boolean`
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:250](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L250)
+
+___
+
+### isNumber
+
+▸ **isNumber**(`value`): `boolean`
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `value` | `unknown` |
+
+#### Returns
+
+`boolean`
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:249](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L249)
+
+[fake-pev-shopping](#readmemd) / [routes/api-products](#modulesroutes_api_productsmd) /
+
+# Namespace:
+
+[routes/api-products](#modulesroutes_api_productsmd).
+
+## Table of contents
+
+### Namespaces
+
+- [addReview](#modulesroutes_api_products_internal_addreviewmd)
+
+### Functions
+
+- [addProduct](#addproduct)
+- [addReview](#addreview)
+- [deleteProduct](#deleteproduct)
+- [getProductById](#getproductbyid)
+- [getProducts](#getproducts)
+- [modifyProduct](#modifyproduct)
+
+## Functions
+
+### addProduct
+
+▸ **addProduct**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:165](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L165)
+
+___
+
+### addReview
+
+▸ **addReview**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:181](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L181)
+
+___
+
+### deleteProduct
+
+▸ **deleteProduct**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:284](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L284)
+
+___
+
+### getProductById
+
+▸ **getProductById**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:145](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L145)
+
+___
+
+### getProducts
+
+▸ **getProducts**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:82](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L82)
+
+___
+
+### modifyProduct
+
+▸ **modifyProduct**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:257](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L257)
+
+[fake-pev-shopping](#readmemd) / routes/api-products
+
+# Module: routes/api-products
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesroutes_api_products_internal_md)
+
+### Variables
+
+- [router](#router)
+
+## Variables
+
+### router
+
+• `Const` **router**: `Router` & `Partial`<{ `_addProduct`: typeof [`addProduct`](#addproduct) ; `_addReview`: typeof [`addReview`](#addreview) ; `_deleteProduct`: typeof [`deleteProduct`](#deleteproduct) ; `_getProductById`: typeof [`getProductById`](#getproductbyid) ; `_getProducts`: typeof [`getProducts`](#getproducts) ; `_modifyProduct`: typeof [`modifyProduct`](#modifyproduct) }\>
+
+#### Defined in
+
+[src/middleware/routes/api-products.ts:18](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-products.ts#L18)
+
+[fake-pev-shopping](#readmemd) / [routes/api-user-roles](#modulesroutes_api_user_rolesmd) /
+
+# Namespace:
+
+[routes/api-user-roles](#modulesroutes_api_user_rolesmd).
+
+## Table of contents
+
+### Type Aliases
+
+- [TMiddlewareFn](#tmiddlewarefn)
+
+## Type Aliases
+
+### TMiddlewareFn
+
+Ƭ **TMiddlewareFn**: (`req`: `Request`, `res`: `Response`, `next`: `NextFunction`) => `Promise`<`void` \| `Response`\>
+
+#### Type declaration
+
+▸ (`req`, `res`, `next`): `Promise`<`void` \| `Response`\>
+
+##### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request` |
+| `res` | `Response` |
+| `next` | `NextFunction` |
+
+##### Returns
+
+`Promise`<`void` \| `Response`\>
+
+#### Defined in
+
+[src/middleware/routes/api-user-roles.ts:13](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-user-roles.ts#L13)
+
+[fake-pev-shopping](#readmemd) / routes/api-user-roles
+
+# Module: routes/api-user-roles
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesroutes_api_user_roles_internal_md)
+
+### Variables
+
+- [router](#router)
+
+## Variables
+
+### router
+
+• `Const` **router**: `Router` & `Partial`<{ `_getUserRoles`: [`TMiddlewareFn`](#tmiddlewarefn) }\>
+
+#### Defined in
+
+[src/middleware/routes/api-user-roles.ts:16](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-user-roles.ts#L16)
+
+[fake-pev-shopping](#readmemd) / [routes/api-users](#modulesroutes_api_usersmd) /
+
+# Namespace:
+
+[routes/api-users](#modulesroutes_api_usersmd).
+
+## Table of contents
+
+### Type Aliases
+
+- [TUserPublic](#tuserpublic)
+
+### Functions
+
+- [addProductToObserved](#addproducttoobserved)
+- [changePassword](#changepassword)
+- [confirmRegistration](#confirmregistration)
+- [deleteUser](#deleteuser)
+- [getObservedProducts](#getobservedproducts)
+- [getUser](#getuser)
+- [logInUser](#loginuser)
+- [logOutUser](#logoutuser)
+- [logOutUserFromSessions](#logoutuserfromsessions)
+- [registerUser](#registeruser)
+- [removeAllProductsFromObserved](#removeallproductsfromobserved)
+- [removeProductFromObserved](#removeproductfromobserved)
+- [resendConfirmRegistration](#resendconfirmregistration)
+- [resendResetPassword](#resendresetpassword)
+- [resetPassword](#resetpassword)
+- [setNewPassword](#setnewpassword)
+- [updateUser](#updateuser)
+
+## Type Aliases
+
+### TUserPublic
+
+Ƭ **TUserPublic**: `Pick`<`IUser`, ``"login"`` \| ``"email"`` \| ``"observedProductsIDs"``\> & { `_id`: `Schema.Types.ObjectId` ; `accountType`: `NonNullable`<`IUser`[``"accountType"``]\>[``"roleName"``] }
+
+#### Defined in
+
+[src/database/models/_user.ts:242](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/database/models/_user.ts#L242)
+
+## Functions
+
+### addProductToObserved
+
+▸ **addProductToObserved**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:519](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L519)
+
+___
+
+### changePassword
+
+▸ **changePassword**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:368](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L368)
+
+___
+
+### confirmRegistration
+
+▸ **confirmRegistration**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:266](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L266)
+
+___
+
+### deleteUser
+
+▸ **deleteUser**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:610](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L610)
+
+___
+
+### getObservedProducts
+
+▸ **getObservedProducts**(`req`, `res`, `next`): `Promise`<``null`` \| `void` \| `any`[] \| `Response`<`any`, `Record`<`string`, `any`\>\> \| `IProduct` \| `IUser` \| `IUserRole` \| `PaginateResult`<`IProduct` \| `IUser` \| `IUserRole`\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> & { `_OMIT_HTTP?`: `boolean` } |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<``null`` \| `void` \| `any`[] \| `Response`<`any`, `Record`<`string`, `any`\>\> \| `IProduct` \| `IUser` \| `IUserRole` \| `PaginateResult`<`IProduct` \| `IUser` \| `IUserRole`\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:583](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L583)
+
+___
+
+### getUser
+
+▸ **getUser**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:493](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L493)
+
+___
+
+### logInUser
+
+▸ **logInUser**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:325](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L325)
+
+___
+
+### logOutUser
+
+▸ **logOutUser**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:455](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L455)
+
+___
+
+### logOutUserFromSessions
+
+▸ **logOutUserFromSessions**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:471](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L471)
+
+___
+
+### registerUser
+
+▸ **registerUser**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:233](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L233)
+
+___
+
+### removeAllProductsFromObserved
+
+▸ **removeAllProductsFromObserved**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:567](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L567)
+
+___
+
+### removeProductFromObserved
+
+▸ **removeProductFromObserved**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:543](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L543)
+
+___
+
+### resendConfirmRegistration
+
+▸ **resendConfirmRegistration**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:293](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L293)
+
+___
+
+### resendResetPassword
+
+▸ **resendResetPassword**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:423](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L423)
+
+___
+
+### resetPassword
+
+▸ **resetPassword**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:391](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L391)
+
+___
+
+### setNewPassword
+
+▸ **setNewPassword**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:191](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L191)
+
+___
+
+### updateUser
+
+▸ **updateUser**(`req`, `res`, `next`): `Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
+| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |
+| `next` | `NextFunction` |
+
+#### Returns
+
+`Promise`<`void` \| `Response`<`any`, `Record`<`string`, `any`\>\>\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:159](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L159)
+
+[fake-pev-shopping](#readmemd) / routes/api-users
+
+# Module: routes/api-users
+
+## Table of contents
+
+### Namespaces
+
+- [<internal\>](#modulesroutes_api_users_internal_md)
+
+### Variables
+
+- [router](#router)
+
+## Variables
+
+### router
+
+• `Const` **router**: `Router` & `Partial`<{ `_addProductToObserved`: typeof [`addProductToObserved`](#addproducttoobserved) ; `_changePassword`: typeof [`changePassword`](#changepassword) ; `_confirmRegistration`: typeof [`confirmRegistration`](#confirmregistration) ; `_deleteUser`: typeof [`deleteUser`](#deleteuser) ; `_getObservedProducts`: typeof [`getObservedProducts`](#getobservedproducts) ; `_getUser`: typeof [`getUser`](#getuser) ; `_logInUser`: typeof [`logInUser`](#loginuser) ; `_logOutUser`: typeof [`logOutUser`](#logoutuser) ; `_logOutUserFromSessions`: typeof [`logOutUserFromSessions`](#logoutuserfromsessions) ; `_registerUser`: typeof [`registerUser`](#registeruser) ; `_removeAllProductsFromObserved`: typeof [`removeAllProductsFromObserved`](#removeallproductsfromobserved) ; `_removeProductFromObserved`: typeof [`removeProductFromObserved`](#removeproductfromobserved) ; `_resendConfirmRegistration`: typeof [`resendConfirmRegistration`](#resendconfirmregistration) ; `_resendResetPassword`: typeof [`resendResetPassword`](#resendresetpassword) ; `_resetPassword`: typeof [`resetPassword`](#resetpassword) ; `_setNewPassword`: typeof [`setNewPassword`](#setnewpassword) ; `_updateUser`: typeof [`updateUser`](#updateuser) }\>
+
+#### Defined in
+
+[src/middleware/routes/api-users.ts:17](https://github.com/ScriptyChris/Fake-PEV-Shopping/blob/9a4d1fa/src/middleware/routes/api-users.ts#L17)
diff --git a/commons/logger.ts b/commons/logger.ts
index 93329a00..cae16674 100644
--- a/commons/logger.ts
+++ b/commons/logger.ts
@@ -1,6 +1,13 @@
+/**
+ * Custom wrapper for a commonly used global `console` methods.
+ * @module
+ */
+
import { basename } from 'path';
-// TODO: improve typing to avoid repeating method declarations
+/**
+ * @ignore
+ */
abstract class Log {
// eslint-disable-next-line @typescript-eslint/no-empty-function
public log(...args: any[]): void {}
@@ -10,6 +17,9 @@ abstract class Log {
public error(...args: any[]): void {}
}
+/**
+ * @ignore
+ */
class Logger extends Log {
private readonly loggingEnabled: boolean;
private readonly msgPrefix: string;
@@ -44,6 +54,11 @@ class Logger extends Log {
}
}
+/**
+ * Creates a module bound logger, which name will be visually emphased in output logs.
+ * @example Log output for `middleware-index` module
+ * ([Module: middleware-index.js]):: Server is listening on port 3000
+ */
function getLogger(moduleFileName: string): Logger {
if (moduleFileName.endsWith('.spec.js')) {
throw TypeError('Logger may not be used in *.spec.js files!');
diff --git a/src/types.ts b/commons/types.ts
similarity index 90%
rename from src/types.ts
rename to commons/types.ts
index 121409d8..1c72317a 100644
--- a/src/types.ts
+++ b/commons/types.ts
@@ -1,5 +1,19 @@
+/**
+ * Common types for whole app.
+ * @module
+ */
+
+/**
+ * @ignore
+ */
import userSessionService from '@frontend/features/userSessionService';
+/**
+ * @ignore
+ */
import storageService from '@frontend/features/storageService';
+/**
+ * @ignore
+ */
import storeService from '@frontend/features/storeService';
export interface IProductInOrder {
@@ -66,12 +80,21 @@ export interface IOrder {
export type TPagination = { pageNumber: number; productsPerPage: number };
+/**
+ * @ignore
+ */
export type TE2E = {
+ /** @ignore */
userSessionService: typeof userSessionService;
+ /** @ignore */
storeService: typeof storeService;
+ /** @ignore */
storageService: typeof storageService;
};
+/**
+ * @ignore
+ */
export type TE2EUser = {
login: string;
password: string;
diff --git a/docker/Dockerfile b/docker/Dockerfile
index b61cade9..2826a9c3 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -13,6 +13,7 @@ COPY \
.eslintrc.js \
.prettierrc \
tsconfig* \
+ generate-grouped-api-docs.js \
webpack.config.js \
./
diff --git a/docker/docker-compose.app-standalone-volumes.yml b/docker/docker-compose.app-standalone-volumes.yml
new file mode 100644
index 00000000..367e5992
--- /dev/null
+++ b/docker/docker-compose.app-standalone-volumes.yml
@@ -0,0 +1,9 @@
+services:
+ node:
+ volumes:
+ - pev-node_modules:/app/node_modules
+ - pev-dist:/app/dist
+
+volumes:
+ pev-node_modules:
+ pev-dist:
\ No newline at end of file
diff --git a/docker/docker-compose.e2e-ci_cd.yml b/docker/docker-compose.e2e-ci_cd.yml
new file mode 100644
index 00000000..2c08f94f
--- /dev/null
+++ b/docker/docker-compose.e2e-ci_cd.yml
@@ -0,0 +1,7 @@
+services:
+ cypress:
+ volumes:
+ - pev-node_modules:/app/node_modules
+ - pev-dist:/app/dist
+ environment:
+ - CYPRESS_TEST_MODE=CI/CD
\ No newline at end of file
diff --git a/docker/docker-compose.services-override.yml b/docker/docker-compose.services-override.yml
deleted file mode 100644
index 68916599..00000000
--- a/docker/docker-compose.services-override.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-services:
- node:
- volumes:
- - pev-node_modules:/app/node_modules
- - pev-dist:/app/dist
-
- cypress:
- volumes:
- - pev-node_modules:/app/node_modules
- - pev-dist:/app/dist
- environment:
- - CYPRESS_TEST_MODE=CI/CD
-
-volumes:
- pev-node_modules:
- pev-dist:
\ No newline at end of file
diff --git a/generate-grouped-api-docs.js b/generate-grouped-api-docs.js
new file mode 100644
index 00000000..9d2d15d9
--- /dev/null
+++ b/generate-grouped-api-docs.js
@@ -0,0 +1,58 @@
+const groups = {
+ middleware: [
+ './src/middleware/features/auth.ts',
+ './src/middleware/helpers/mailer.ts',
+ './src/middleware/helpers/middleware-error-handler.ts',
+ './src/middleware/helpers/middleware-response-wrapper.ts',
+ './src/middleware/routes/api-config.ts',
+ './src/middleware/routes/api-orders.ts',
+ './src/middleware/routes/api-product-categories.ts',
+ './src/middleware/routes/api-products.ts',
+ './src/middleware/routes/api-user-roles.ts',
+ './src/middleware/routes/api-users.ts',
+ ],
+ database: ['./src/database/populate/populate.ts', './src/database/api.ts', './src/database/models/index.ts'],
+ frontend: [
+ './src/frontend/components/pages/_routes.ts',
+ './src/frontend/components/utils/bodyObserver.tsx',
+ './src/frontend/components/utils/flexibleList.jsx',
+ './src/frontend/components/utils/pagination.jsx',
+ './src/frontend/components/utils/pevElements.jsx',
+ './src/frontend/components/utils/popup.jsx',
+ './src/frontend/components/utils/ratingWidget.jsx',
+ './src/frontend/components/utils/scroller.jsx',
+ './src/frontend/contexts/rwd-layout.tsx',
+ './src/frontend/features/httpService.ts',
+ './src/frontend/features/storageService.ts',
+ './src/frontend/features/storeService.ts',
+ './src/frontend/features/userSessionService.ts',
+ ],
+ commons: ['./commons/logger.ts', './commons/types.ts'],
+};
+
+////////
+////////
+
+if (!require('fs').existsSync('./typedoc.json')) {
+ return console.log('TypeDoc config not found - script is probably run by Docker - abort generating docs!');
+}
+
+const { execSync } = require('child_process');
+const { rmSync } = require('fs');
+const execSyncOpts = { stdio: 'inherit' };
+const apiDocsDirPath = `./api-docs/`;
+
+for (const [groupName, groupedFiles] of Object.entries(groups)) {
+ const docsPath = `${apiDocsDirPath}${groupName}`;
+ const concatenatedPath = `${apiDocsDirPath}${groupName}.md`;
+
+ // generate docs
+ execSync(`node_modules/.bin/typedoc ${groupedFiles.join(' ')} --out ${docsPath}`, execSyncOpts);
+ // merge generated docs in single files related to modules
+ execSync(
+ `node_modules/.bin/concat-md --decrease-title-levels --hide-anchor-links ${docsPath} > ${concatenatedPath}`,
+ execSyncOpts
+ );
+ // cleanup after generating process
+ rmSync(`${apiDocsDirPath}${groupName}`, { recursive: true });
+}
diff --git a/package-lock.json b/package-lock.json
index 6c4135fc..0a85e599 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -58,13 +58,10 @@
}
},
"json5": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
- "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true
},
"ms": {
"version": "2.1.2",
@@ -2561,6 +2558,27 @@
"@sinonjs/commons": "^1.7.0"
}
},
+ "@textlint/ast-node-types": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-4.4.3.tgz",
+ "integrity": "sha512-qi2jjgO6Tn3KNPGnm6B7p6QTEPvY95NFsIAaJuwbulur8iJUEenp1OnoUfiDaC/g2WPPEFkcfXpmnu8XEMFo2A==",
+ "dev": true
+ },
+ "@textlint/markdown-to-ast": {
+ "version": "6.0.9",
+ "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-6.0.9.tgz",
+ "integrity": "sha512-hfAWBvTeUGh5t5kTn2U3uP3qOSM1BSrxzl1jF3nn0ywfZXpRBZr5yRjXnl4DzIYawCtZOshmRi/tI3/x4TE1jQ==",
+ "dev": true,
+ "requires": {
+ "@textlint/ast-node-types": "^4.0.3",
+ "debug": "^2.1.3",
+ "remark-frontmatter": "^1.2.0",
+ "remark-parse": "^5.0.0",
+ "structured-source": "^3.0.2",
+ "traverse": "^0.6.6",
+ "unified": "^6.1.6"
+ }
+ },
"@tootallnate/once": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -2799,6 +2817,12 @@
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
"dev": true
},
+ "@types/minimist": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
+ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==",
+ "dev": true
+ },
"@types/mongodb": {
"version": "3.6.6",
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.6.tgz",
@@ -3558,6 +3582,12 @@
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"dev": true
},
+ "@zamiell/typedoc-plugin-not-exported": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/@zamiell/typedoc-plugin-not-exported/-/typedoc-plugin-not-exported-0.2.0.tgz",
+ "integrity": "sha512-R0EOvUfSc7APvBL5ZRkW3J1g/McWnMrVeVaIwrCmz9IiWjQ8LuLumRQxRICuiCz9FEwa3Giz/7SJXbbLf8bQ3A==",
+ "dev": true
+ },
"abab": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
@@ -3573,6 +3603,7 @@
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "dev": true,
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
@@ -3685,6 +3716,23 @@
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
+ "anchor-markdown-header": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/anchor-markdown-header/-/anchor-markdown-header-0.5.7.tgz",
+ "integrity": "sha512-AmikqcK15r3q99hPvTa1na9n3eLkW0uE+RL9BZMSgwYalQeDnNXbYrN06BIcBPfGlmsGIE2jvkuvl/x0hyPF5Q==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "~6.1.0"
+ },
+ "dependencies": {
+ "emoji-regex": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.3.tgz",
+ "integrity": "sha512-73/zxHTjP2N2FQf0J5ngNjxP9LqG2krUshxYaowI8HxZQsiL2pYJc3k9/O93fc5/lCSkZv+bQ5Esk6k6msiSvg==",
+ "dev": true
+ }
+ }
+ },
"ansi-colors": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
@@ -3849,6 +3897,12 @@
"function-bind": "^1.1.1"
}
},
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+ "dev": true
+ },
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -4404,6 +4458,12 @@
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
"dev": true
},
+ "bail": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+ "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "dev": true
+ },
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -4564,6 +4624,60 @@
"integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
"dev": true
},
+ "body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "object-inspect": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="
+ },
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ }
+ }
+ },
"bonjour": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
@@ -4584,6 +4698,12 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
},
+ "boundary": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/boundary/-/boundary-1.0.1.tgz",
+ "integrity": "sha512-AaLhxHwYVh55iOTJncV3DE5o7RakEUSSj64XXEWRTiIhlp7aDI8qR0vY/k8Uw0Z234VjZi/iG/WxfrvqYPUCww==",
+ "dev": true
+ },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -4883,7 +5003,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dev": true,
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
@@ -4977,6 +5096,24 @@
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
"dev": true
},
+ "character-entities": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "dev": true
+ },
+ "character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "dev": true
+ },
+ "character-reference-invalid": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+ "dev": true
+ },
"check-more-types": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
@@ -5228,6 +5365,12 @@
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
+ "collapse-white-space": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+ "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+ "dev": true
+ },
"collect-v8-coverage": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
@@ -5334,6 +5477,371 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
+ "concat-md": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/concat-md/-/concat-md-0.5.0.tgz",
+ "integrity": "sha512-PmGLIZDLKknKk+KqHgFqcW7lpTsAgmMDnZA20ElhgoqlXs+9hcWplpUOfzoQcWDEF/HndnkOTxapwf4YtUKE8Q==",
+ "dev": true,
+ "requires": {
+ "doctoc": "^1.4.0",
+ "front-matter": "^4.0.2",
+ "globby": "^11.1.0",
+ "lodash.startcase": "^4.4.0",
+ "meow": "^9.0.0",
+ "transform-markdown-links": "^2.0.0"
+ },
+ "dependencies": {
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "camelcase-keys": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+ "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "map-obj": "^4.0.0",
+ "quick-lru": "^4.0.1"
+ }
+ },
+ "fast-glob": {
+ "version": "3.2.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ }
+ },
+ "hosted-git-info": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+ "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
+ "is-core-module": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+ "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "map-obj": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+ "dev": true
+ },
+ "meow": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
+ "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==",
+ "dev": true,
+ "requires": {
+ "@types/minimist": "^1.2.0",
+ "camelcase-keys": "^6.2.2",
+ "decamelize": "^1.2.0",
+ "decamelize-keys": "^1.1.0",
+ "hard-rejection": "^2.1.0",
+ "minimist-options": "4.1.0",
+ "normalize-package-data": "^3.0.0",
+ "read-pkg-up": "^7.0.1",
+ "redent": "^3.0.0",
+ "trim-newlines": "^3.0.0",
+ "type-fest": "^0.18.0",
+ "yargs-parser": "^20.2.3"
+ }
+ },
+ "micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ }
+ },
+ "normalize-package-data": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
+ "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^4.0.1",
+ "is-core-module": "^2.5.0",
+ "semver": "^7.3.4",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "requires": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "dependencies": {
+ "hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "dev": true
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "dev": true
+ }
+ }
+ },
+ "read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ }
+ }
+ },
+ "redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dev": true,
+ "requires": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ }
+ },
+ "semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "requires": {
+ "min-indent": "^1.0.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "trim-newlines": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+ "dev": true
+ },
+ "type-fest": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
+ "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "dev": true
+ }
+ }
+ },
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
@@ -5399,14 +5907,14 @@
}
},
"cookie": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
- "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"copy-concurrently": {
"version": "1.0.5",
@@ -5560,9 +6068,9 @@
}
},
"json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"loader-utils": {
@@ -5949,9 +6457,9 @@
"dev": true
},
"json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"loader-utils": {
@@ -6382,6 +6890,16 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
+ "decamelize-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
+ "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
+ "dev": true,
+ "requires": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ }
+ },
"decimal.js": {
"version": "10.3.1",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
@@ -6389,9 +6907,9 @@
"dev": true
},
"decode-uri-component": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ=="
},
"deep-equal": {
"version": "1.1.1",
@@ -6525,7 +7043,8 @@
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "dev": true
},
"des.js": {
"version": "1.0.1",
@@ -6538,9 +7057,9 @@
}
},
"destroy": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
- "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
},
"detect-file": {
"version": "1.0.0",
@@ -6639,6 +7158,20 @@
"buffer-indexof": "^1.0.0"
}
},
+ "doctoc": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/doctoc/-/doctoc-1.4.0.tgz",
+ "integrity": "sha512-8IAq3KdMkxhXCUF+xdZxdJxwuz8N2j25sMgqiu4U4JWluN9tRKMlAalxGASszQjlZaBprdD2YfXpL3VPWUD4eg==",
+ "dev": true,
+ "requires": {
+ "@textlint/markdown-to-ast": "~6.0.9",
+ "anchor-markdown-header": "^0.5.5",
+ "htmlparser2": "~3.9.2",
+ "minimist": "~1.2.0",
+ "underscore": "~1.8.3",
+ "update-section": "^0.3.0"
+ }
+ },
"doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -6666,6 +7199,24 @@
"csstype": "^3.0.2"
}
},
+ "dom-serializer": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+ "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ },
+ "dependencies": {
+ "domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true
+ }
+ }
+ },
"dom-walk": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
@@ -6678,6 +7229,12 @@
"integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
"dev": true
},
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
"domexception": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@@ -6695,6 +7252,25 @@
}
}
},
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "domutils": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+ "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
"dot-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
@@ -6769,7 +7345,7 @@
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"elliptic": {
"version": "6.5.4",
@@ -6815,7 +7391,7 @@
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
},
"end-of-stream": {
"version": "1.4.4",
@@ -7249,13 +7825,10 @@
}
},
"json5": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
- "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true
},
"loader-utils": {
"version": "2.0.0",
@@ -7450,7 +8023,7 @@
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
},
"eventemitter2": {
"version": "6.4.5",
@@ -7600,95 +8173,91 @@
}
},
"express": {
- "version": "4.17.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz",
- "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==",
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
"requires": {
- "accepts": "~1.3.7",
+ "accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.19.1",
+ "body-parser": "1.20.1",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.4.1",
+ "cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
- "depd": "~1.1.2",
+ "depd": "2.0.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "~1.1.2",
+ "finalhandler": "1.2.0",
"fresh": "0.5.2",
+ "http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.7",
- "qs": "6.9.6",
+ "qs": "6.11.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
- "send": "0.17.2",
- "serve-static": "1.14.2",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
"setprototypeof": "1.2.0",
- "statuses": "~1.5.0",
+ "statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"dependencies": {
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
},
- "body-parser": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz",
- "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==",
- "requires": {
- "bytes": "3.1.1",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "http-errors": "1.8.1",
- "iconv-lite": "0.4.24",
- "on-finished": "~2.3.0",
- "qs": "6.9.6",
- "raw-body": "2.4.2",
- "type-is": "~1.6.18"
- }
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
},
- "bytes": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz",
- "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg=="
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
- "http-errors": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
- "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.1"
+ "mime-db": "1.52.0"
}
},
- "qs": {
- "version": "6.9.6",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz",
- "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ=="
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
},
- "raw-body": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz",
- "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==",
+ "object-inspect": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="
+ },
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"requires": {
- "bytes": "3.1.1",
- "http-errors": "1.8.1",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
+ "side-channel": "^1.0.4"
}
},
"safe-buffer": {
@@ -7696,15 +8265,20 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
- "setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
},
- "toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
}
},
@@ -7904,6 +8478,15 @@
"reusify": "^1.0.4"
}
},
+ "fault": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
+ "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
+ "dev": true,
+ "requires": {
+ "format": "^0.2.0"
+ }
+ },
"faye-websocket": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
@@ -7989,17 +8572,24 @@
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ=="
},
"finalhandler": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
- "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "statuses": "~1.5.0",
+ "statuses": "2.0.1",
"unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ }
}
},
"find-cache-dir": {
@@ -8657,6 +9247,12 @@
"mime-types": "^2.1.12"
}
},
+ "format": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
+ "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==",
+ "dev": true
+ },
"formik": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/formik/-/formik-2.2.9.tgz",
@@ -8695,7 +9291,7 @@
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
},
"from2": {
"version": "2.3.0",
@@ -8707,6 +9303,15 @@
"readable-stream": "^2.0.0"
}
},
+ "front-matter": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz",
+ "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==",
+ "dev": true,
+ "requires": {
+ "js-yaml": "^3.13.1"
+ }
+ },
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@@ -8781,8 +9386,7 @@
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"functional-red-black-tree": {
"version": "1.0.1",
@@ -8850,7 +9454,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
- "dev": true,
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
@@ -9063,6 +9666,27 @@
"integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
"dev": true
},
+ "handlebars": {
+ "version": "4.7.7",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
+ "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.0",
+ "source-map": "^0.6.1",
+ "uglify-js": "^3.1.4",
+ "wordwrap": "^1.0.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -9079,11 +9703,16 @@
"har-schema": "^2.0.0"
}
},
+ "hard-rejection": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+ "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+ "dev": true
+ },
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
"requires": {
"function-bind": "^1.1.1"
}
@@ -9106,8 +9735,7 @@
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
- "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
- "dev": true
+ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
},
"has-unicode": {
"version": "2.0.1",
@@ -9351,12 +9979,58 @@
"util.promisify": "1.0.0"
}
},
+ "htmlparser2": {
+ "version": "3.9.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
+ "integrity": "sha512-RSOwLNCnCLDRB9XpSfCzsLzzX8COezhJ3D4kRBNWh0NC/facp1hAMmM8zD7kC01My8vD6lGEbPMlbRW/EwGK5w==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.0",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.2"
+ },
+ "dependencies": {
+ "entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ }
+ }
+ },
"http-deceiver": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
"integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=",
"dev": true
},
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "dependencies": {
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ }
+ }
+ },
"http-proxy": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
@@ -9630,6 +10304,22 @@
"kind-of": "^3.0.2"
}
},
+ "is-alphabetical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+ "dev": true
+ },
+ "is-alphanumerical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+ "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+ "dev": true,
+ "requires": {
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0"
+ }
+ },
"is-arguments": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
@@ -9696,6 +10386,12 @@
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
"dev": true
},
+ "is-decimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+ "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "dev": true
+ },
"is-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
@@ -9785,6 +10481,12 @@
"is-extglob": "^1.0.0"
}
},
+ "is-hexadecimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "dev": true
+ },
"is-in-browser": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
@@ -9921,12 +10623,24 @@
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
"dev": true
},
+ "is-whitespace-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+ "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+ "dev": true
+ },
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
"dev": true
},
+ "is-word-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+ "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+ "dev": true
+ },
"is-wsl": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
@@ -12078,6 +12792,12 @@
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
},
+ "jsonc-parser": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
+ "dev": true
+ },
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -12438,9 +13158,9 @@
},
"dependencies": {
"json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -12529,6 +13249,12 @@
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
},
+ "lodash.startcase": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
+ "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
+ "dev": true
+ },
"log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -12727,6 +13453,12 @@
"yallist": "^3.0.2"
}
},
+ "lunr": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
+ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
+ "dev": true
+ },
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@@ -12773,6 +13505,18 @@
"object-visit": "^1.0.0"
}
},
+ "markdown-escapes": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+ "dev": true
+ },
+ "marked": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
+ "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==",
+ "dev": true
+ },
"math-random": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
@@ -12794,7 +13538,7 @@
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
},
"memfs": {
"version": "3.3.0",
@@ -12842,7 +13586,7 @@
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
},
"merge-stream": {
"version": "2.0.0",
@@ -12859,7 +13603,7 @@
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
},
"micromatch": {
"version": "2.3.11",
@@ -12934,6 +13678,12 @@
"dom-walk": "^0.1.0"
}
},
+ "min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true
+ },
"mini-create-react-context": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz",
@@ -12982,6 +13732,25 @@
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
+ "minimist-options": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+ "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+ "dev": true,
+ "requires": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0",
+ "kind-of": "^6.0.3"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ }
+ }
+ },
"minipass": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz",
@@ -13336,7 +14105,8 @@
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "dev": true
},
"neo-async": {
"version": "2.6.2",
@@ -14110,9 +14880,9 @@
"dev": true
},
"on-finished": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"requires": {
"ee-first": "1.1.1"
}
@@ -14316,6 +15086,20 @@
"safe-buffer": "^5.1.1"
}
},
+ "parse-entities": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
+ "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
+ "dev": true,
+ "requires": {
+ "character-entities": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "character-reference-invalid": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-hexadecimal": "^1.0.0"
+ }
+ },
"parse-glob": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
@@ -14426,7 +15210,7 @@
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"path-type": {
"version": "4.0.0",
@@ -14924,6 +15708,12 @@
"integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==",
"dev": true
},
+ "quick-lru": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+ "dev": true
+ },
"randomatic": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
@@ -14976,6 +15766,24 @@
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
+ "raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ }
+ }
+ },
"react": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
@@ -15605,6 +16413,39 @@
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
"dev": true
},
+ "remark-frontmatter": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-1.3.3.tgz",
+ "integrity": "sha512-fM5eZPBvu2pVNoq3ZPW22q+5Ativ1oLozq2qYt9I2oNyxiUd/tDl0iLLntEVAegpZIslPWg1brhcP1VsaSVUag==",
+ "dev": true,
+ "requires": {
+ "fault": "^1.0.1",
+ "xtend": "^4.0.1"
+ }
+ },
+ "remark-parse": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz",
+ "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==",
+ "dev": true,
+ "requires": {
+ "collapse-white-space": "^1.0.2",
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "is-word-character": "^1.0.0",
+ "markdown-escapes": "^1.0.0",
+ "parse-entities": "^1.1.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "trim": "0.0.1",
+ "trim-trailing-lines": "^1.0.0",
+ "unherit": "^1.0.4",
+ "unist-util-remove-position": "^1.0.0",
+ "vfile-location": "^2.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -15724,6 +16565,12 @@
"is-finite": "^1.0.0"
}
},
+ "replace-ext": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+ "integrity": "sha512-vuNYXC7gG7IeVNBC1xUllqCcZKRbJoSPOBhnTEcAIiKCsbuef6zO3F0Rve3isPMMoNoQRWjQwbAgAjHUHniyEA==",
+ "dev": true
+ },
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@@ -16327,9 +17174,9 @@
},
"dependencies": {
"json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"loader-utils": {
@@ -16434,51 +17281,39 @@
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"send": {
- "version": "0.17.2",
- "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
- "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"requires": {
"debug": "2.6.9",
- "depd": "~1.1.2",
- "destroy": "~1.0.4",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
- "http-errors": "1.8.1",
+ "http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
- "on-finished": "~2.3.0",
+ "on-finished": "2.4.1",
"range-parser": "~1.2.1",
- "statuses": "~1.5.0"
+ "statuses": "2.0.1"
},
"dependencies": {
- "http-errors": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
- "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
- "requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.1"
- }
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
- "setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
}
},
@@ -16533,14 +17368,14 @@
}
},
"serve-static": {
- "version": "1.14.2",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
- "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
- "send": "0.17.2"
+ "send": "0.18.0"
}
},
"set-blocking": {
@@ -16577,6 +17412,11 @@
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
"dev": true
},
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
"sha.js": {
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
@@ -16615,6 +17455,17 @@
"dev": true,
"optional": true
},
+ "shiki": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz",
+ "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==",
+ "dev": true,
+ "requires": {
+ "jsonc-parser": "^3.0.0",
+ "vscode-oniguruma": "^1.6.1",
+ "vscode-textmate": "5.2.0"
+ }
+ },
"side-channel": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz",
@@ -17083,6 +17934,12 @@
}
}
},
+ "state-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+ "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+ "dev": true
+ },
"static-extend": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@@ -17107,7 +17964,8 @@
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
- "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "dev": true
},
"stdout-stream": {
"version": "1.4.1",
@@ -17310,6 +18168,15 @@
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
},
+ "structured-source": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-3.0.2.tgz",
+ "integrity": "sha512-Ap7JHfKgmH40SUjumqyKTHYHNZ8GvGQskP34ks0ElHCDEig+bYGpmXVksxPSrgcY9rkJqhVMzfeg5GIpZelfpQ==",
+ "dev": true,
+ "requires": {
+ "boundary": "^1.0.1"
+ }
+ },
"style-loader": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
@@ -17321,9 +18188,9 @@
},
"dependencies": {
"json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"loader-utils": {
@@ -17666,6 +18533,11 @@
}
}
},
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -17705,6 +18577,24 @@
"punycode": "^2.1.1"
}
},
+ "transform-markdown-links": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/transform-markdown-links/-/transform-markdown-links-2.0.0.tgz",
+ "integrity": "sha512-hZNifdoeeaNK37AAAUPqDgCyyAypszOPERwCNpzrZutnxKpqt1OcssojU0ewS0f6ffhRfsSjYiXiml48hp5RdQ==",
+ "dev": true
+ },
+ "traverse": {
+ "version": "0.6.7",
+ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz",
+ "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==",
+ "dev": true
+ },
+ "trim": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+ "integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==",
+ "dev": true
+ },
"trim-newlines": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
@@ -17717,6 +18607,18 @@
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
"dev": true
},
+ "trim-trailing-lines": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz",
+ "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==",
+ "dev": true
+ },
+ "trough": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "dev": true
+ },
"true-case-path": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
@@ -17746,13 +18648,10 @@
},
"dependencies": {
"json5": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
- "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true
},
"lru-cache": {
"version": "6.0.0",
@@ -17904,18 +18803,108 @@
"is-typedarray": "^1.0.0"
}
},
+ "typedoc": {
+ "version": "0.22.18",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.18.tgz",
+ "integrity": "sha512-NK9RlLhRUGMvc6Rw5USEYgT4DVAUFk7IF7Q6MYfpJ88KnTZP7EneEa4RcP+tX1auAcz7QT1Iy0bUSZBYYHdoyA==",
+ "dev": true,
+ "requires": {
+ "glob": "^8.0.3",
+ "lunr": "^2.3.9",
+ "marked": "^4.0.16",
+ "minimatch": "^5.1.0",
+ "shiki": "^0.10.1"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
+ "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ }
+ },
+ "minimatch": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
+ "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ }
+ }
+ },
+ "typedoc-plugin-markdown": {
+ "version": "3.12.1",
+ "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.12.1.tgz",
+ "integrity": "sha512-gMntJq7+JlGJZ5sVjrkzO/rG2dsmNBbWk5ZkcKvYu6QOeBwGcK5tzEyS0aqnFTJj9GCHCB+brAnTuKtAyotNwA==",
+ "dev": true,
+ "requires": {
+ "handlebars": "^4.7.7"
+ }
+ },
+ "typedoc-plugin-missing-exports": {
+ "version": "0.22.6",
+ "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.22.6.tgz",
+ "integrity": "sha512-1uguGQqa+c5f33nWS3v1mm0uAx4Ii1lw4Kx2zQksmYFKNEWTmrmMXbMNBoBg4wu0p4dFCNC7JIWPoRzpNS6pFA==",
+ "dev": true
+ },
+ "typedoc-plugin-rename-defaults": {
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.4.tgz",
+ "integrity": "sha512-0rAeNttAfu6ixbi1yu6d+DqNZN8SfRivj2QbnZ4zVa+5HcCPcmQrlR6WHjNzdDfpkGytiiqPTtRD6pAfW/yACg==",
+ "dev": true
+ },
"typescript": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
"dev": true
},
+ "uglify-js": {
+ "version": "3.17.4",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
+ "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
+ "dev": true,
+ "optional": true
+ },
"undefsafe": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
"dev": true
},
+ "underscore": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
+ "integrity": "sha512-5WsVTFcH1ut/kkhAaHf4PVgI8c7++GiVcpCGxPouI6ZVjsqPnSDf8h/8HtVqc0t4fzRXwnMK70EcZeAs3PIddg==",
+ "dev": true
+ },
+ "unherit": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+ "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@@ -17944,6 +18933,20 @@
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
"dev": true
},
+ "unified": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz",
+ "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==",
+ "dev": true,
+ "requires": {
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-plain-obj": "^1.1.0",
+ "trough": "^1.0.0",
+ "vfile": "^2.0.0",
+ "x-is-string": "^0.1.0"
+ }
+ },
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@@ -17980,6 +18983,45 @@
"imurmurhash": "^0.1.4"
}
},
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ },
+ "unist-util-remove-position": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
+ "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^1.1.0"
+ }
+ },
+ "unist-util-stringify-position": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
+ "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==",
+ "dev": true
+ },
+ "unist-util-visit": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
+ "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit-parents": "^2.0.0"
+ }
+ },
+ "unist-util-visit-parents": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
+ "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ }
+ },
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@@ -17989,7 +19031,7 @@
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
},
"unset-value": {
"version": "1.0.0",
@@ -18049,6 +19091,12 @@
"integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
"dev": true
},
+ "update-section": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/update-section/-/update-section-0.3.3.tgz",
+ "integrity": "sha512-BpRZMZpgXLuTiKeiu7kK0nIPwGdyrqrs6EDSaXtjD/aQ2T+qVo9a5hRC3HN3iJjCMxNT/VxoLGQ7E/OzE5ucnw==",
+ "dev": true
+ },
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -18145,7 +19193,7 @@
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
},
"uuid": {
"version": "8.3.2",
@@ -18224,12 +19272,51 @@
"extsprintf": "^1.2.0"
}
},
+ "vfile": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
+ "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.4",
+ "replace-ext": "1.0.0",
+ "unist-util-stringify-position": "^1.0.0",
+ "vfile-message": "^1.0.0"
+ }
+ },
+ "vfile-location": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
+ "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==",
+ "dev": true
+ },
+ "vfile-message": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz",
+ "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==",
+ "dev": true,
+ "requires": {
+ "unist-util-stringify-position": "^1.1.1"
+ }
+ },
"vm-browserify": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
"dev": true
},
+ "vscode-oniguruma": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
+ "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
+ "dev": true
+ },
+ "vscode-textmate": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz",
+ "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==",
+ "dev": true
+ },
"w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@@ -19770,6 +20857,12 @@
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true
},
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+ "dev": true
+ },
"worker-farm": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
@@ -19862,6 +20955,12 @@
"async-limiter": "~1.0.0"
}
},
+ "x-is-string": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
+ "integrity": "sha512-GojqklwG8gpzOVEVki5KudKNoq7MbbjYZCbyWzEz7tyPA7eleiE0+ePwOWQQRb5fm86rD3S8Tc0tSFf3AOv50w==",
+ "dev": true
+ },
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
diff --git a/package.json b/package.json
index 31755bce..fec20372 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,7 @@
"test:unit:dev": "jest --watch --env=node test/unit",
"test:unit:debug": "node --inspect-brk node_modules/jest/bin/jest.js --runInBand",
"test:e2e:dev": "cd ./docker && xhost +local: && sudo docker-compose -f docker-compose.yml -f docker-compose.e2e.yml --env-file ../.env up",
- "test:e2e:CI_CD": "cd ./docker && sudo docker-compose -f docker-compose.yml -f docker-compose.e2e.yml -f docker-compose.services-override.yml --env-file ../.env up --abort-on-container-exit",
+ "test:e2e:CI_CD": "cd ./docker && sudo docker-compose -f docker-compose.yml -f docker-compose.app-standalone-volumes.yml -f docker-compose.e2e.yml -f docker-compose.e2e-ci_cd.yml --env-file ../.env up --abort-on-container-exit",
"populate-db": "ts-node --files --project tsconfig.backend.json src/database/populate/populate.ts executedFromCLI=true",
"prepare-commons": "npm run eslint:commons && npm run prettier:commons",
"dev:frontend": "webpack-dev-server --env development",
@@ -42,7 +42,9 @@
"build:backend": "rimraf dist/src/middleware dist/src/database dist/commons && tsc --project tsconfig.backend.json",
"build:frontend": "rimraf dist/src/frontend/ && webpack --env production",
"build": "npm run build:backend && npm run build:frontend && npm run prepare-commons",
+ "postbuild": "npm run generate-api-docs",
"debug": "cross-env BACKEND_ONLY=true node --inspect-brk dist/src/middleware/middleware-index.js",
+ "generate-api-docs": "node generate-grouped-api-docs.js",
"serve": "node_modules/.bin/cross-env BACKEND_ONLY=true node dist/src/middleware/middleware-index.js"
},
"devDependencies": {
@@ -65,9 +67,11 @@
"@types/webpack-dev-server": "^3.11.1",
"@typescript-eslint/eslint-plugin": "^4.15.2",
"@typescript-eslint/parser": "^4.15.2",
+ "@zamiell/typedoc-plugin-not-exported": "^0.2.0",
"babel-cli": "^6.26.0",
"babel-loader": "^8.1.0",
"babel-preset-react-app": "^9.1.2",
+ "concat-md": "^0.5.0",
"copy-webpack-plugin": "^6.0.4",
"css-loader": "^4.2.1",
"cypress": "^9.1.1",
@@ -94,6 +98,10 @@
"style-loader": "^1.3.0",
"ts-jest": "^26.5.1",
"ts-node": "^9.1.1",
+ "typedoc": "^0.22.18",
+ "typedoc-plugin-markdown": "^3.12.1",
+ "typedoc-plugin-missing-exports": "^0.22.6",
+ "typedoc-plugin-rename-defaults": "^0.6.4",
"typescript": "^4.1.3",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12",
@@ -106,7 +114,7 @@
"classnames": "^2.3.1",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
- "express": "^4.17.2",
+ "express": "^4.18.2",
"formik": "^2.2.9",
"jsonwebtoken": "^8.5.1",
"mobx": "^5.15.6",
diff --git a/src/augmentations.d.ts b/src/augmentations.d.ts
index 65425789..3a7392ff 100644
--- a/src/augmentations.d.ts
+++ b/src/augmentations.d.ts
@@ -1,5 +1,5 @@
import type { DeleteWriteOpResultObject } from 'mongodb';
-import type { TE2E } from './types';
+import type { TE2E } from '@commons/types';
import type { Cypress } from 'local-cypress';
import type { IUser } from '@database/models';
diff --git a/src/database/api.ts b/src/database/api.ts
index de5ccf11..ce1692fb 100644
--- a/src/database/api.ts
+++ b/src/database/api.ts
@@ -1,3 +1,8 @@
+/**
+ * Facade over database CRUD operations.
+ * @module
+ */
+
import {
getModel,
TCOLLECTION_NAMES,
diff --git a/src/database/models/__core-and-commons.ts b/src/database/models/__core-and-commons.ts
index 0e7ea3b5..05125895 100644
--- a/src/database/models/__core-and-commons.ts
+++ b/src/database/models/__core-and-commons.ts
@@ -1,3 +1,8 @@
+/**
+ * @module
+ * @notExported
+ */
+
import mongoose from 'mongoose';
// fix `isValidObjectId` lost `this`
export const isValidObjectId = mongoose.isValidObjectId.bind(mongoose);
diff --git a/src/database/models/_product.ts b/src/database/models/_product.ts
index 3e8c3bdf..bf469e0d 100644
--- a/src/database/models/_product.ts
+++ b/src/database/models/_product.ts
@@ -1,3 +1,8 @@
+/**
+ * @module
+ * @notExported
+ */
+
import { Document, Types, Schema, model, COLLECTION_NAMES } from '@database/models/__core-and-commons';
import mongoosePaginate from 'mongoose-paginate-v2';
import getLogger from '@commons/logger';
@@ -156,11 +161,17 @@ export type TProductPublic = Pick<
export type TProductToPopulate = Exclude;
+/**
+ * @internal
+ */
export interface IReviews extends Types.Subdocument {
list: Record[];
averageRating: number;
}
+/**
+ * @internal
+ */
export interface IProduct extends Document {
name: string;
url: string;
diff --git a/src/database/models/_user.ts b/src/database/models/_user.ts
index 34f44e76..aa815db3 100644
--- a/src/database/models/_user.ts
+++ b/src/database/models/_user.ts
@@ -1,3 +1,8 @@
+/**
+ * @module
+ * @notExported
+ */
+
import { model, Schema, Document, Model, TUserRoleName, COLLECTION_NAMES } from '@database/models/__core-and-commons';
import { randomBytes } from 'crypto';
import { getToken, comparePasswords } from '@middleware/features/auth';
@@ -243,11 +248,17 @@ export type TUserToPopulate = Pick {
validateNewUserPayload(newUser: any): string;
validatePassword(password: unknown): string;
}
+/**
+ * @internal
+ */
export interface IUser extends Document {
login: string;
password: string;
diff --git a/src/database/models/_userRole.ts b/src/database/models/_userRole.ts
index 2fb32f2b..f2c3670f 100644
--- a/src/database/models/_userRole.ts
+++ b/src/database/models/_userRole.ts
@@ -1,3 +1,8 @@
+/**
+ * @module
+ * @notExported
+ */
+
import {
Schema,
model,
@@ -33,6 +38,9 @@ userRoleSchema.methods.toJSON = function () {
export const UserRoleModel = model(COLLECTION_NAMES.User_Role, userRoleSchema);
export type TUserRoleModel = typeof UserRoleModel;
+/**
+ * @internal
+ */
export interface IUserRole extends Document {
roleName: TUserRoleName;
owners: Schema.Types.ObjectId[];
diff --git a/src/database/models/index.ts b/src/database/models/index.ts
index 82348db7..0575086f 100644
--- a/src/database/models/index.ts
+++ b/src/database/models/index.ts
@@ -1,3 +1,8 @@
+/**
+ * Groups and re-exports lower level types and values related to working with database'es models.
+ * @module
+ */
+
import { ProductModel, IProduct } from './_product';
import { UserModel, IUser } from './_user';
import { UserRoleModel, IUserRole } from './_userRole';
@@ -13,6 +18,9 @@ export const getModel = (modelName: T) => MODELS[mo
export type TDocuments = IProduct | IUser | IUserRole;
export type TSort = { [key: string]: 1 | -1 };
+/**
+ * @group Re-export of database models and their related entities.
+ */
export * from './_product';
export * from './_user';
export * from './_userRole';
diff --git a/src/database/populate/populate.ts b/src/database/populate/populate.ts
index 5a29d954..d1ba417b 100644
--- a/src/database/populate/populate.ts
+++ b/src/database/populate/populate.ts
@@ -1,3 +1,18 @@
+/**
+ * Populates database with indicated initial data, optionally doing a cleanup beforehand.
+ * @module
+ * @example npm usage
+ * ```sh
+ * npm run populate-db
+ * ```
+ * @example Manual CLI usage
+ * ```sh
+ * ts-node src/database/populate/populate.tspopulate.ts \
+ * executedFromCLI=true \
+ * products__InputPath=path/to/JSON/with/initial/products/data
+ * ```
+ */
+
// TODO: [DX] activate `moduleAliasesResolvers.js` beforehand, so module alias can be used here
import { COLLECTION_NAMES, TCOLLECTION_NAMES } from '../models/__core-and-commons';
@@ -13,7 +28,11 @@ const CAPITALIZED_PLURAL_COLLECTION_NAMES = Object.fromEntries(
})
) as TCapitalizedPluralCollectionsMap;
-const PARAMS = Object.freeze({
+/**
+ * Maps supported params passed via CLI.
+ * @notExported
+ */
+const PARAMS = {
EXECUTED_FROM_CLI: 'executedFromCLI',
CLEAN_ALL_BEFORE: 'cleanAllBefore',
JSON_FILE_PATH: {
@@ -21,13 +40,17 @@ const PARAMS = Object.freeze({
[CAPITALIZED_PLURAL_COLLECTION_NAMES.USERS]: 'users__InputPath',
[CAPITALIZED_PLURAL_COLLECTION_NAMES.USER_ROLES]: 'user_roles__InputPath',
},
-});
-const DEFAULT_PARAMS = Object.freeze({
+} as const;
+/**
+ * Maps default params, which are applied when regarding individual params are not provided via CLI.
+ * @notExported
+ */
+const DEFAULT_PARAMS = {
[PARAMS.CLEAN_ALL_BEFORE]: 'true',
[PARAMS.JSON_FILE_PATH.PRODUCTS]: './initialData/products.json',
[PARAMS.JSON_FILE_PATH.USERS]: './initialData/users.json',
[PARAMS.JSON_FILE_PATH.USER_ROLES]: './initialData/user_roles.json',
-});
+} as const;
if (getScriptParamStringValue(PARAMS.EXECUTED_FROM_CLI)) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -87,6 +110,10 @@ if (!getScriptParamStringValue(PARAMS.JSON_FILE_PATH.PRODUCTS)) {
throw ReferenceError(`CLI argument "${PARAMS.JSON_FILE_PATH.PRODUCTS}" must be provided as non empty string!`);
}
+/**
+ * Executes database population. May be called from other module or it's automatically called when this script is run from CLI.
+ * @param shouldCleanupAll - Decides whether do database cleanup. Passing `PARAMS.CLEAN_ALL_BEFORE` via CLI is an alternative way to do cleanup.
+ */
const executeDBPopulation = async (shouldCleanupAll = false) => {
logger.log('executeDBPopulation() called.');
@@ -253,7 +280,8 @@ function updateRelatedProductsNames(sourceDataList: TProductToPopulate[]): Promi
}
function getScriptParamStringValue(paramName: string) {
- const paramValue = process.argv.find((arg) => arg.includes(paramName)) ?? DEFAULT_PARAMS[paramName];
+ const paramValue =
+ process.argv.find((arg) => arg.includes(paramName)) ?? DEFAULT_PARAMS[paramName as keyof typeof DEFAULT_PARAMS];
// not using `logger`, because this function might be called before `logger` initialization (to resolve module aliases)
console.log('[getScriptParamValue()] /paramName:', paramName, '/paramValue:', paramValue);
diff --git a/src/frontend/components/pages/_routes.ts b/src/frontend/components/pages/_routes.ts
index 6dd0445f..e037223e 100644
--- a/src/frontend/components/pages/_routes.ts
+++ b/src/frontend/components/pages/_routes.ts
@@ -1,9 +1,15 @@
+/**
+ * Encapsulates routing paths and methods (such as helpers and guards).
+ * @module
+ */
+
import queryString from 'query-string';
import type { useHistory } from 'react-router-dom';
+/** @internal */
import type { TStoreService } from '@frontend/features/storeService';
import { ARRAY_FORMAT_SEPARATOR } from '@commons/consts';
-const ROUTE_GROUPS = Object.freeze({
+const ROUTE_GROUPS = {
ROOT: '/',
PAGES: '/pages',
get PRODUCTS() {
@@ -12,9 +18,9 @@ const ROUTE_GROUPS = Object.freeze({
get ACCOUNT() {
return `${this.PAGES}/account`;
},
-});
+} as const;
-export const ROUTES = Object.freeze({
+export const ROUTES = {
ROOT: ROUTE_GROUPS.ROOT,
PAGES: ROUTE_GROUPS.PAGES,
REGISTER: `${ROUTE_GROUPS.PAGES}/register`,
@@ -48,14 +54,14 @@ export const ROUTES = Object.freeze({
get ACCOUNT__ORDERS() {
return `${this.ACCOUNT}/orders`;
},
-});
+} as const;
const QUERY_PARAMS_CONFIG = {
arrayFormat: 'bracket-separator',
arrayFormatSeparator: ARRAY_FORMAT_SEPARATOR,
} as const;
-export const routeHelpers = Object.freeze({
+export const routeHelpers = {
createModifyProductUrl(productName: string) {
return ROUTES.PRODUCTS__MODIFY_PRODUCT.replace(/:\w+/, productName);
},
@@ -88,7 +94,7 @@ export const routeHelpers = Object.freeze({
});
};
},
-});
+} as const;
export const useRoutesGuards = (storeService: TStoreService) => {
return {
diff --git a/src/frontend/components/svgIcons.jsx b/src/frontend/components/svgIcons.jsx
index 0ed6469d..77739f37 100644
--- a/src/frontend/components/svgIcons.jsx
+++ b/src/frontend/components/svgIcons.jsx
@@ -1,3 +1,8 @@
+/*
+ Factory components for SVG icons, which are not provided by currently used MUI,
+ hence are either custom created or borrowed from other 3rd-party sources.
+*/
+
import React from 'react';
import classNames from 'classnames';
diff --git a/src/frontend/components/utils/bodyObserver.tsx b/src/frontend/components/utils/bodyObserver.tsx
index 2ac296e9..2eae457d 100644
--- a/src/frontend/components/utils/bodyObserver.tsx
+++ b/src/frontend/components/utils/bodyObserver.tsx
@@ -1,6 +1,12 @@
+/**
+ * Handles HTML `` style changes, which affect position of components,
+ * such as `ScrollToTop` button and `ProductComparisonCandidates` bar.
+ * @module
+ */
+
type TSubscriptionCallback = {
- subscriptionID: number,
- (bodyStyle: CSSStyleDeclaration): void,
+ subscriptionID: number;
+ (bodyStyle: CSSStyleDeclaration): void;
};
let nextMutationSubscriptionID = 0;
@@ -13,6 +19,10 @@ const bodyObserver = new MutationObserver((mutations) => {
});
bodyObserver.observe(document.body, { attributes: true });
+/**
+ * Subscribes a provided `callback` to `` style mutations.
+ * @returns subscriptionID, which lets unsubscribing `callback` later.
+ */
export const subscribeToBodyMutations = (callback: TSubscriptionCallback) => {
callback.subscriptionID = nextMutationSubscriptionID++;
bodyMutationSubscribers.push(callback);
@@ -20,6 +30,9 @@ export const subscribeToBodyMutations = (callback: TSubscriptionCallback) => {
return callback.subscriptionID;
};
+/**
+ * Unsubscribes previously subscribed `callback` (via it's ID) from `` style mutations.
+ */
export const unSubscribeFromBodyMutations = (subscriptionID: number) => {
const subscriptionCallbackIndex = bodyMutationSubscribers.findIndex(
(callback) => callback.subscriptionID === subscriptionID
diff --git a/src/frontend/components/utils/flexibleList.jsx b/src/frontend/components/utils/flexibleList.jsx
index da7f6f32..d4d5101b 100644
--- a/src/frontend/components/utils/flexibleList.jsx
+++ b/src/frontend/components/utils/flexibleList.jsx
@@ -1,3 +1,8 @@
+/**
+ * Flexible list component, which allows adding, editing and deleting it's items in a customizable way.
+ * @module
+ */
+
import React, { useState, useEffect, useReducer, useMemo } from 'react';
import classNames from 'classnames';
diff --git a/src/frontend/components/utils/pagination.jsx b/src/frontend/components/utils/pagination.jsx
index 736a434d..3a8e1e22 100644
--- a/src/frontend/components/utils/pagination.jsx
+++ b/src/frontend/components/utils/pagination.jsx
@@ -1,3 +1,7 @@
+/**
+ * @module
+ */
+
import React from 'react';
import ReactPaginate from 'react-paginate';
diff --git a/src/frontend/components/utils/pevElements.jsx b/src/frontend/components/utils/pevElements.jsx
index fc500b34..a93d7bbc 100644
--- a/src/frontend/components/utils/pevElements.jsx
+++ b/src/frontend/components/utils/pevElements.jsx
@@ -1,3 +1,8 @@
+/**
+ * Facade over commonly used MUI and native HTML elements.
+ * @module
+ */
+
import React, { forwardRef, useState, useMemo, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { Formik, Field, Form } from 'formik';
diff --git a/src/frontend/components/utils/popup.jsx b/src/frontend/components/utils/popup.jsx
index 9f50b5e1..1c07d9f6 100644
--- a/src/frontend/components/utils/popup.jsx
+++ b/src/frontend/components/utils/popup.jsx
@@ -1,3 +1,7 @@
+/**
+ * @module
+ */
+
import React, { useCallback, memo, useState, useEffect, useRef } from 'react';
import Dialog from '@material-ui/core/Dialog';
@@ -15,6 +19,9 @@ const POPUP_TYPES = {
FAILURE: 'FAILURE',
};
+/**
+ * Factory for popup's default closing button.
+ */
const getClosePopupBtn = (setPopupData) => {
if (typeof setPopupData !== 'function') {
throw TypeError(`setPopupData should be a function! Received: ${setPopupData}`);
@@ -44,6 +51,9 @@ const getClosePopupBtn = (setPopupData) => {
// }
// };
+/**
+ * Generic error popup component is hooked on {@link HttpService} to present user any errors in more friendly way.
+ */
const GenericErrorPopup = memo(function GenericErrorPopup() {
const [popupData, setPopupData] = useState(null);
const subscriptionHandler = useCallback((exceptionValue) => {
diff --git a/src/frontend/components/utils/ratingWidget.jsx b/src/frontend/components/utils/ratingWidget.jsx
index 764a33cd..3bb756c6 100644
--- a/src/frontend/components/utils/ratingWidget.jsx
+++ b/src/frontend/components/utils/ratingWidget.jsx
@@ -1,3 +1,7 @@
+/**
+ * @module
+ */
+
import React, { useState } from 'react';
import classNames from 'classnames';
diff --git a/src/frontend/components/utils/scroller.jsx b/src/frontend/components/utils/scroller.jsx
index 92d24b88..a428fefc 100644
--- a/src/frontend/components/utils/scroller.jsx
+++ b/src/frontend/components/utils/scroller.jsx
@@ -1,3 +1,7 @@
+/**
+ * @module
+ */
+
import React, { useMemo, useEffect, useRef, useState, useCallback } from 'react';
import { createPortal } from 'react-dom';
diff --git a/src/frontend/contexts/mui-theme.tsx b/src/frontend/contexts/mui-theme.tsx
index 7dafa14f..ac68c299 100644
--- a/src/frontend/contexts/mui-theme.tsx
+++ b/src/frontend/contexts/mui-theme.tsx
@@ -5,7 +5,7 @@ import { unstable_createMuiStrictModeTheme, createMuiTheme } from '@material-ui/
// eslint-disable-next-line no-var
declare var __IS_DEV_MODE__: string;
-function MUIThemeProvider({ children }) {
+function MUIThemeProvider({ children }: React.PropsWithChildren>) {
// TODO: [DX] refactor this after migrating to React v18 and MUI v5
// https://github.com/mui/material-ui/issues/13394
diff --git a/src/frontend/contexts/rwd-layout.tsx b/src/frontend/contexts/rwd-layout.tsx
index c6142a8a..fee58733 100644
--- a/src/frontend/contexts/rwd-layout.tsx
+++ b/src/frontend/contexts/rwd-layout.tsx
@@ -1,6 +1,11 @@
+/**
+ * Observes DOM viewport changes and emits information about the currently established one.
+ * @module
+ */
+
import React, { createContext, useState, useMemo, useEffect } from 'react';
-const RWDLayoutContext = createContext(undefined);
+const RWDLayoutContext = createContext({});
const mediaQueryList = (() => {
const documentStyles = window.getComputedStyle(document.documentElement);
@@ -11,7 +16,9 @@ const mediaQueryList = (() => {
.trim()
.replace(/\\a|\s{2,}/g, '');
- const mql: TMQLWithName = window.matchMedia(mediaQuery);
+ const mql = window.matchMedia(mediaQuery) as ReturnType & {
+ __deviceName: string;
+ };
const deviceName = queryName.match(/(?<=--)\w+/)?.[0];
if (!deviceName) {
@@ -32,7 +39,7 @@ const useRWDMediaQuery = () => {
);
useEffect(() => {
- function onMQLChange({ matches, media }) {
+ function onMQLChange({ matches, media }: MediaQueryListEvent) {
if (matches) {
const matchedMediaName = mediaQueryList.find((mql) => media === mql.media)?.__deviceName;
@@ -49,7 +56,7 @@ const useRWDMediaQuery = () => {
return () => mediaQueryList.forEach((mql) => mql.removeEventListener('change', onMQLChange));
}, []);
- const mediaQueryCheckers = useMemo(
+ const mediaQueryCheckers = useMemo>(
() =>
mediaQueryList.reduce((output, { __deviceName: mqName }) => {
const upperCasedMQName = `${mqName[0].toUpperCase()}${mqName.slice(1)}`;
@@ -69,7 +76,7 @@ const useRWDMediaQuery = () => {
return mediaQueryCheckers;
};
-function RWDLayoutProvider({ children }) {
+function RWDLayoutProvider({ children }: React.PropsWithChildren>) {
return {children};
}
diff --git a/src/frontend/features/httpService.ts b/src/frontend/features/httpService.ts
index 1a61516a..0f45c62d 100644
--- a/src/frontend/features/httpService.ts
+++ b/src/frontend/features/httpService.ts
@@ -1,3 +1,8 @@
+/**
+ * Handles HTTP communication between frontend and backend.
+ * @module
+ */
+
import type { IUser, TUserPublic, TUserRegistrationCredentials, IProduct } from '@database/models';
import type {
IEmbracedResponse,
@@ -6,25 +11,38 @@ import type {
TServerErrorHTTPStatusCodesToData,
} from '@middleware/helpers/middleware-response-wrapper';
import type { TProductTechnicalSpecs } from '@middleware/helpers/api-products-specs-mapper';
-import { HTTP_STATUS_CODE, IOrder, TPagination } from '@src/types';
+import { HTTP_STATUS_CODE, IOrder, TPagination } from '@commons/types';
import storeService from '@frontend/features/storeService';
import { possiblyReEncodeURI } from '@commons/uriReEncoder';
import { routeHelpers } from '@frontend/components/pages/_routes';
type TResDataType = T[keyof T];
+/**
+ * Handles (low level) HTTP actions as:
+ * - setting appropriate headers,
+ * - assembling requests regarding URL, params, payload, etc. according to used HTTP method and backend expectance,
+ * - initially parsing responses,
+ * - initially handling HTTP errors.
+ */
class Ajax {
+ /** @internal */
_API_PATH_NAME: string;
+ /** @internal */
_BASE_API_URL: string;
+ /** @internal */
_AUTH_TOKEN: string | null;
+ /** @internal */
HTTP_METHOD_NAME = {
GET: 'GET',
PATCH: 'PATCH',
POST: 'POST',
DELETE: 'DELETE',
} as const;
+ /** @internal */
_isGenericErrorHandlerActive: boolean;
+ /** @internal */
constructor() {
this._API_PATH_NAME = 'api';
this._BASE_API_URL = `${location.origin}/${this._API_PATH_NAME}`;
@@ -32,6 +50,7 @@ class Ajax {
this._isGenericErrorHandlerActive = true;
}
+ /** @internal */
get _BASE_API_URL_OBJECT() {
const urlObject = new URL(location.origin);
urlObject.pathname = `${this._API_PATH_NAME}/`;
@@ -39,36 +58,43 @@ class Ajax {
return urlObject;
}
+ /** @internal */
_getContentTypeHeader() {
return {
'Content-Type': 'application/json',
};
}
+ /** @internal */
_getAuthHeader() {
return `Bearer ${this.getAuthToken() || ''}`;
}
+ /** @internal */
getAuthToken() {
return this._AUTH_TOKEN;
}
+ /** @internal */
setAuthToken(authToken: this['_AUTH_TOKEN']) {
this._AUTH_TOKEN = authToken;
}
+ /** @internal */
disableGenericErrorHandler() {
this._isGenericErrorHandlerActive = false;
return this;
}
+ /** @internal */
_enableGenericErrorHandler() {
this._isGenericErrorHandlerActive = true;
return this;
}
+ /** @internal */
_fetchBaseHandler(fetchResult: ReturnType) {
const isGenericErrorHandlerActive = this._isGenericErrorHandlerActive;
const fetchPromise = fetchResult
@@ -118,6 +144,7 @@ class Ajax {
return fetchPromise;
}
+ /** @internal */
_sendRequestWithPayload(methodName: string, apiEndpoint: string, data: unknown, useToken: boolean) {
const headers = new Headers(this._getContentTypeHeader());
@@ -135,6 +162,7 @@ class Ajax {
}
// TODO: fix creating URL by apiEndpoint
+ /** @internal */
getRequest(apiEndpoint: { url: string; searchParams: URLSearchParams | string } | string, useToken = false) {
const url = this._BASE_API_URL_OBJECT;
@@ -163,14 +191,17 @@ class Ajax {
return this._fetchBaseHandler(fetch(url.toString(), options));
}
+ /** @internal */
postRequest(apiEndpoint: string, data: unknown, useToken = false) {
return this._sendRequestWithPayload(this.HTTP_METHOD_NAME.POST, apiEndpoint, data, useToken);
}
+ /** @internal */
patchRequest(apiEndpoint: string, data: unknown, useToken = false) {
return this._sendRequestWithPayload(this.HTTP_METHOD_NAME.PATCH, apiEndpoint, data, useToken);
}
+ /** @internal */
deleteRequest(apiEndpoint: string, useToken = false) {
const url = this._BASE_API_URL_OBJECT;
url.pathname += apiEndpoint;
@@ -189,7 +220,10 @@ class Ajax {
}
}
-const httpService = new (class HttpService extends Ajax {
+/**
+ * Intermediates (high level) client actions meant to communicate with backend APIs.
+ */
+class HttpService extends Ajax {
private URLS = {
PRODUCTS: 'products',
PRODUCT_CATEGORIES: 'productCategories',
@@ -214,10 +248,16 @@ const httpService = new (class HttpService extends Ajax {
searchParams.append('limit', String(pagination.productsPerPage));
}
+ /**
+ * Adds a new product.
+ */
addProduct(product: IProduct) {
return this.postRequest(this.URLS.PRODUCTS, product, true);
}
+ /**
+ * Gets products according to optional constraints like: name, price, pagination etc.
+ */
getProducts(
initialSearchParams: Partial<{
name: IProduct['name'];
@@ -266,6 +306,9 @@ const httpService = new (class HttpService extends Ajax {
return this.getRequest(`${this.URLS.PRODUCTS}?idList=${idList}`);
}
+ /**
+ * Gets products by list of names - mostly useful for retrieving related products of a single one.
+ */
getProductsByNames(nameList: IProduct['name'][]) {
const searchParams = new URLSearchParams({ nameList: JSON.stringify(nameList) });
@@ -275,6 +318,9 @@ const httpService = new (class HttpService extends Ajax {
});
}
+ /**
+ * Gets products by a single name - mostly useful for search feature.
+ */
getProductsByName(name: IProduct['name'], pagination: TPagination, getOnlyEssentialData = true) {
const searchParams = new URLSearchParams();
searchParams.append('name', name);
@@ -285,6 +331,9 @@ const httpService = new (class HttpService extends Ajax {
return this.getRequest({ url: this.URLS.PRODUCTS, searchParams });
}
+ /**
+ * Gets product by it's URL - mostly useful for retrieving product from browser's address bar.
+ */
getProductByUrl(url: IProduct['url']) {
const searchParams = new URLSearchParams();
@@ -298,16 +347,25 @@ const httpService = new (class HttpService extends Ajax {
// return this.getRequest(`${this.URLS.PRODUCTS}/${id}`);
// }
+ /**
+ * Gets categories of all products.
+ */
getProductCategories() {
return this.getRequest(this.URLS.PRODUCT_CATEGORIES);
}
+ /**
+ * Gets technical specifications of all products.
+ */
getProductsSpecifications() {
return this.getRequest(this.URLS.PRODUCTS_SPECS) as Promise<
TProductTechnicalSpecs | Pick
>;
}
+ /**
+ * Modifies product.
+ */
modifyProduct(productName: IProduct['name'], productModifications: Partial) {
const modifiedProductData = {
name: productName,
@@ -319,14 +377,23 @@ const httpService = new (class HttpService extends Ajax {
return this.patchRequest(this.URLS.PRODUCTS, modifiedProductData);
}
+ /**
+ * Adds a new review to chosen product.
+ */
addProductReview(productName: IProduct['name'], productReview: IProduct['reviews']) {
return this.patchRequest(`${this.URLS.PRODUCTS}/${productName}/add-review`, productReview);
}
+ /**
+ * Delets a product via it's name.
+ */
deleteProduct(productName: IProduct['name']) {
return this.deleteRequest(`${this.URLS.PRODUCTS}/${productName}`, true);
}
+ /**
+ * Gets info about currently logged in user via it's ID taken from app's state.
+ */
getCurrentUser() {
const userId = storeService.userAccountState?._id;
@@ -337,73 +404,125 @@ const httpService = new (class HttpService extends Ajax {
return this.getRequest(`${this.URLS.USERS}/${userId}`, true);
}
+ /**
+ * Starts the process of making a new purchase according to given order details.
+ */
makeOrder(orderDetails: IOrder) {
return this.postRequest(this.URLS.ORDERS, orderDetails);
}
+ /**
+ * Logs in user based on their login and password credentials.
+ */
loginUser(loginCredentials: { login: IUser['login']; password: IUser['password'] }) {
return this.postRequest(`${this.URLS.USERS}/login`, loginCredentials) as Promise<
TUserPublic | Pick
>;
}
+ /**
+ * Resets user password via it's email.
+ */
resetPassword(email: IUser['email']) {
return this.postRequest(`${this.URLS.USERS}/reset-password`, { email });
}
+ /**
+ * Resends (repeats) resetting user password via it's email.
+ */
resendResetPassword(email: IUser['email']) {
return this.postRequest(`${this.URLS.USERS}/resend-reset-password`, { email });
}
+ /**
+ * Loggs out user from current session.
+ */
logoutUser() {
return this.postRequest(`${this.URLS.USERS}/logout`, null, true);
}
+ /**
+ * Loggs out user from all sessions; current session can be preserved if `preseveCurrentSession` param is true.
+ */
logOutUserFromSessions(preseveCurrentSession = false) {
return this.postRequest(`${this.URLS.USERS}/logout-all`, { preseveCurrentSession }, true);
}
+ /**
+ * Gets all user roles.
+ */
getUserRoles() {
return this.getRequest(`${this.URLS.USER_ROLES}`);
}
+ /**
+ * Registers a new user according to provided credentials.
+ */
registerUser(registrationCredentials: TUserRegistrationCredentials) {
return this.postRequest(`${this.URLS.USERS}/register`, registrationCredentials);
}
+ /**
+ * Confirms a newly registered user via token received on their email.
+ */
confirmRegistration(token: NonNullable) {
return this.postRequest(`${this.URLS.USERS}/confirm-registration`, { token });
}
+ /**
+ * Resends registration confirmation email.
+ */
resendConfirmRegistration(email: IUser['email']) {
return this.postRequest(`${this.URLS.USERS}/resend-confirm-registration`, { email });
}
+ /**
+ * Sets a new password for user - mostly after reseting password.
+ */
setNewPassword(newPassword: IUser['password'], token: NonNullable[number]) {
return this.patchRequest(`${this.URLS.USERS}/set-new-password`, { newPassword, token });
}
+ /**
+ * Changes user's current password to a new one.
+ */
changePassword(password: IUser['password'], newPassword: IUser['password']) {
return this.patchRequest(`${this.URLS.USERS}/change-password`, { password, newPassword }, true);
}
+ /**
+ * Adds product to observed by user, so they can more conveniently find it later.
+ */
addProductToObserved(productId: string) {
return this.postRequest(`${this.URLS.USERS}/add-product-to-observed`, { productId }, true);
}
+ /**
+ * Removes product from observed by user.
+ */
removeProductFromObserved(productId: string) {
return this.deleteRequest(`${this.URLS.USERS}/remove-product-from-observed/${productId}`, true);
}
+ /**
+ * Removes all products from observed by user.
+ */
removeAllProductsFromObserved() {
return this.deleteRequest(`${this.URLS.USERS}/remove-all-products-from-observed`, true);
}
+ /**
+ * Retrieves all observed products by user.
+ */
getObservedProducts() {
return this.getRequest(`${this.URLS.USERS}/observed-products`, true);
}
-})();
+}
+/**
+ * Keeps track of {@link HttpService} subscribers, which want to externally hook into any request
+ * that returns certain status.
+ */
const httpServiceSubscriber = (() => {
const _subscribers: Record = {
EXCEPTION: null,
@@ -437,6 +556,9 @@ const httpServiceSubscriber = (() => {
};
})();
+/**
+ * Recognize HTTP responses kinds.
+ */
const CUSTOM_RES_EXT_DICT = Object.freeze({
__NO_CONTENT: '__NO_CONTENT',
__ERROR_TO_HANDLE: '__ERROR_TO_HANDLE',
@@ -451,4 +573,4 @@ interface ICustomResExt {
export { httpServiceSubscriber, CUSTOM_RES_EXT_DICT };
-export default httpService;
+export default new HttpService();
diff --git a/src/frontend/features/storageService.ts b/src/frontend/features/storageService.ts
index 46aab3a1..4855a0a4 100644
--- a/src/frontend/features/storageService.ts
+++ b/src/frontend/features/storageService.ts
@@ -1,8 +1,16 @@
-import type { IUserCart } from '@src/types';
+/**
+ * Handles reading and manipulating browser's LocalStorage data.
+ * @module
+ */
+
+import type { IUserCart } from '@commons/types';
import type { IUser, TUserPublic } from '@database/models';
type TStorageValue = IUserCart | TUserPublic | NonNullable[number] | null;
+/**
+ * Manipulating storage data API for various contexts, such as `UserCart` or `UserAccount`.
+ */
const storageService = (() => {
class StorageService {
key: string;
@@ -11,6 +19,10 @@ const storageService = (() => {
this.key = key;
}
+ /**
+ * Update regarding storage context by either setting given `value` or removing existing one,
+ * depending on result of calling `checkIfShouldRemove`.
+ */
update(value: TStorageValue, checkIfShouldRemove: () => boolean) {
try {
if (checkIfShouldRemove()) {
@@ -24,6 +36,9 @@ const storageService = (() => {
}
}
+ /**
+ * @returns Already parsed (from JSON) stored value.
+ */
get() {
try {
return JSON.parse(String(window.localStorage.getItem(this.key)));
@@ -33,6 +48,9 @@ const storageService = (() => {
}
}
+ /**
+ * Removes a values.
+ */
remove() {
this.update(null, () => true);
}
diff --git a/src/frontend/features/storeService.ts b/src/frontend/features/storeService.ts
index 3d4c3187..4c211e66 100644
--- a/src/frontend/features/storeService.ts
+++ b/src/frontend/features/storeService.ts
@@ -1,6 +1,10 @@
+/**
+ * @module
+ */
+
import { observable, decorate, action } from 'mobx';
import type { TUserPublic } from '@database/models';
-import type { IUserCart } from '@src/types';
+import type { IUserCart } from '@commons/types';
const USER_CART_STATE: IUserCart = {
totalPrice: 0,
@@ -13,8 +17,11 @@ const INITIAL_USER_ACCOUNT_STATE = null;
type TUserCartProduct = IUserCart['products'][number] & { count: number };
class StoreService {
+ /** @internal */
_userAccountState: TUserPublic | null;
+ /** @internal */
_userCartState: IUserCart;
+ /** @internal */
_productComparisonState: TUserCartProduct[];
constructor() {
@@ -24,6 +31,7 @@ class StoreService {
this._productComparisonState = [];
}
+ /** @internal */
_getProductIndex(newUserCartStateName: TUserCartProduct['name']) {
return this._userCartState.products.findIndex((productItem) => productItem.name === newUserCartStateName);
}
@@ -138,15 +146,18 @@ class StoreService {
}
decorate(StoreService, {
+ /** @internal */
_userAccountState: observable,
updateUserAccountState: action,
clearUserAccountState: action,
+ /** @internal */
_userCartState: observable,
addProductToUserCartState: action,
removeProductFromUserCartState: action,
clearUserCartState: action,
+ /** @internal */
_productComparisonState: observable,
updateProductComparisonState: action,
clearProductComparisonState: action,
diff --git a/src/frontend/features/userSessionService.ts b/src/frontend/features/userSessionService.ts
index 3b0ec041..ebe4d0ab 100644
--- a/src/frontend/features/userSessionService.ts
+++ b/src/frontend/features/userSessionService.ts
@@ -1,3 +1,7 @@
+/**
+ * @module
+ */
+
import storeService from './storeService';
import storageService from './storageService';
import httpService, { CUSTOM_RES_EXT_DICT } from './httpService';
@@ -5,7 +9,7 @@ import type { IUser, TUserPublic } from '@database/models';
type TLogInCredentials = Pick;
-const userSessionService = Object.freeze({
+const userSessionService = {
async logIn(logInCredentials: TLogInCredentials) {
return httpService.loginUser(logInCredentials).then((res) => {
if (CUSTOM_RES_EXT_DICT.__EXCEPTION_ALREADY_HANDLED in res) {
@@ -77,7 +81,7 @@ const userSessionService = Object.freeze({
storeService.updateUserAccountState(userAccount);
}
},
-});
+} as const;
if (window.Cypress) {
window.__E2E__.userSessionService = userSessionService;
diff --git a/src/middleware/features/auth.ts b/src/middleware/features/auth.ts
index af9bbe62..65085399 100644
--- a/src/middleware/features/auth.ts
+++ b/src/middleware/features/auth.ts
@@ -1,10 +1,14 @@
+/**
+ * @module
+ */
+
import getLogger from '@commons/logger';
import { compare, hash } from 'bcrypt';
import { sign, verify } from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';
import fetch, { RequestInit, Response as FetchResponse } from 'node-fetch';
import { IUser, TUserRoleName, COLLECTION_NAMES } from '@database/models';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import { wrapRes } from '@middleware/helpers/middleware-response-wrapper';
import { getFromDB } from '@database/api';
import { dotEnv } from '@commons/dotEnvLoader';
@@ -12,6 +16,7 @@ import { dotEnv } from '@commons/dotEnvLoader';
const logger = getLogger(module.filename);
const SALT_ROUNDS = 8;
+/** @internal */
type TToken = { _id: number };
const comparePasswords = (password: string, passwordPattern: string) => {
diff --git a/src/middleware/helpers/mailer.ts b/src/middleware/helpers/mailer.ts
index c9117a81..1e045a2e 100644
--- a/src/middleware/helpers/mailer.ts
+++ b/src/middleware/helpers/mailer.ts
@@ -1,6 +1,10 @@
+/**
+ * @module
+ */
+
import { createTransport } from 'nodemailer';
-import SMTPTransport = require('nodemailer/lib/smtp-transport');
-import SendmailTransport = require('nodemailer/lib/sendmail-transport');
+import SMTPTransport from 'nodemailer/lib/smtp-transport';
+import SendmailTransport from 'nodemailer/lib/sendmail-transport';
import { dotEnv } from '@commons/dotEnvLoader';
const translations = Object.freeze({
diff --git a/src/middleware/helpers/middleware-error-handler.ts b/src/middleware/helpers/middleware-error-handler.ts
index 40ffcd1b..49a696d4 100644
--- a/src/middleware/helpers/middleware-error-handler.ts
+++ b/src/middleware/helpers/middleware-error-handler.ts
@@ -1,6 +1,10 @@
+/**
+ * @module
+ */
+
import type { Request, Response, NextFunction } from 'express';
import type { TLogger } from '@commons/logger';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import { wrapRes } from './middleware-response-wrapper';
type TMiddlewareErrorHandler = (error: Error, req: Request, res: Response) => Pick;
diff --git a/src/middleware/helpers/middleware-response-wrapper.ts b/src/middleware/helpers/middleware-response-wrapper.ts
index 245dca76..02d4aaef 100644
--- a/src/middleware/helpers/middleware-response-wrapper.ts
+++ b/src/middleware/helpers/middleware-response-wrapper.ts
@@ -1,5 +1,10 @@
+/**
+ * Custom wrapper to secure consistent usage of a few {@link https://expressjs.com/en/4x/api.html#res|`Express#res`} methods.
+ * @module
+ */
+
import type { Response } from 'express';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
export interface IEmbracedResponse {
// TODO: [REFACTOR] 'authToken' could be always paired with 'payload' prop or be contained by it
@@ -84,6 +89,19 @@ function wrapRes<
Status extends Exclude,
DataKey extends TDataKeyExt
>(res: Response, status: Status, data: Record): Response;
+/**
+ * It asserts that used `HTTP_STATUS_CODE` is adequate to provided optional payload shape (regarding it's key/label).
+ * @example Without payload
+ * ```ts
+ * wrapRes(res, HTTP_STATUS_CODE.NO_CONTENT);
+ * ```
+ * @example With payload
+ * ```ts
+ * wrapRes(res, HTTP_STATUS_CODE.OK, { payload: someResourceValue });
+ * wrapRes(res, HTTP_STATUS_CODE.CREATED, { message: 'Resource created!' });
+ * wrapRes(res, HTTP_STATUS_CODE.NOT_FOUND, { error: 'Resource not found!' });
+ * ```
+ */
function wrapRes>(
res: Response,
status: Status,
diff --git a/src/middleware/helpers/payu-api.ts b/src/middleware/helpers/payu-api.ts
index 890ef323..f02c3f55 100644
--- a/src/middleware/helpers/payu-api.ts
+++ b/src/middleware/helpers/payu-api.ts
@@ -1,5 +1,5 @@
import fetch from 'node-fetch';
-import { IPayByLinkMethod, IProductInOrder } from '@src/types';
+import { IPayByLinkMethod, IProductInOrder } from '@commons/types';
import getLogger from '@commons/logger';
import { dotEnv } from '@commons/dotEnvLoader';
diff --git a/src/middleware/middleware-index.ts b/src/middleware/middleware-index.ts
index f7592d23..63e0ae9c 100644
--- a/src/middleware/middleware-index.ts
+++ b/src/middleware/middleware-index.ts
@@ -21,7 +21,7 @@ import apiProductCategories from './routes/api-product-categories';
import apiUsers from './routes/api-users';
import apiUserRoles from './routes/api-user-roles';
import apiOrders from './routes/api-orders';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import { wrapRes } from '@middleware/helpers/middleware-response-wrapper';
import { getPopulationState } from '@database/connector';
import { dotEnv } from '@commons/dotEnvLoader';
diff --git a/src/middleware/routes/api-config.ts b/src/middleware/routes/api-config.ts
index f0046c67..d2005b6d 100644
--- a/src/middleware/routes/api-config.ts
+++ b/src/middleware/routes/api-config.ts
@@ -1,7 +1,11 @@
+/**
+ * @module
+ */
+
import getLogger from '@commons/logger';
import { Router } from 'express';
import type { Request, Response, NextFunction } from 'express';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import getMiddlewareErrorHandler from '@middleware/helpers/middleware-error-handler';
import { wrapRes } from '@middleware/helpers/middleware-response-wrapper';
import { executeDBPopulation } from '@database/populate/populate';
diff --git a/src/middleware/routes/api-orders.ts b/src/middleware/routes/api-orders.ts
index 1df7a760..4ef92d5c 100644
--- a/src/middleware/routes/api-orders.ts
+++ b/src/middleware/routes/api-orders.ts
@@ -1,9 +1,13 @@
+/**
+ * @module
+ */
+
import getLogger from '@commons/logger';
import { Router, Request, Response, NextFunction } from 'express';
import fetch, { RequestInit, Response as FetchResponse } from 'node-fetch';
import { getFromDB } from '@database/api';
import { authToPayU as getToken } from '@middleware/features/auth';
-import { HTTP_STATUS_CODE, IPayByLinkMethod, IProductInOrder } from '@src/types';
+import { HTTP_STATUS_CODE, IPayByLinkMethod, IProductInOrder } from '@commons/types';
import { getMinAndMaxPrice, getOrderBody, getOrderHeaders, getOrderPaymentMethod } from '@middleware/helpers/payu-api';
import { wrapRes, TypeOfHTTPStatusCodes } from '@middleware/helpers/middleware-response-wrapper';
import getMiddlewareErrorHandler from '@middleware/helpers/middleware-error-handler';
diff --git a/src/middleware/routes/api-product-categories.ts b/src/middleware/routes/api-product-categories.ts
index 741785bc..ce701cfb 100644
--- a/src/middleware/routes/api-product-categories.ts
+++ b/src/middleware/routes/api-product-categories.ts
@@ -1,7 +1,11 @@
+/**
+ * @module
+ */
+
import getLogger from '@commons/logger';
import { Router, Request, Response, NextFunction } from 'express';
import { getFromDB } from '@database/api';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import getMiddlewareErrorHandler from '@middleware/helpers/middleware-error-handler';
import { wrapRes } from '@middleware/helpers/middleware-response-wrapper';
import { COLLECTION_NAMES } from '@database/models';
diff --git a/src/middleware/routes/api-products.ts b/src/middleware/routes/api-products.ts
index 95ad17c6..1b5bf707 100644
--- a/src/middleware/routes/api-products.ts
+++ b/src/middleware/routes/api-products.ts
@@ -1,3 +1,7 @@
+/**
+ * @module
+ */
+
import getLogger from '@commons/logger';
import { Router, Request, Response, NextFunction } from 'express';
import { authMiddlewareFn as authMiddleware, userRoleMiddlewareFn } from '@middleware/features/auth';
@@ -5,7 +9,7 @@ import { getFromDB, saveToDB, updateOneModelInDB, deleteFromDB } from '@database
import { queryBuilder } from '@database/utils/queryBuilder';
import mapProductsTechnicalSpecs from '@middleware/helpers/api-products-specs-mapper';
import { IProduct, IReviews, COLLECTION_NAMES, USER_ROLES_MAP } from '@database/models';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import getMiddlewareErrorHandler from '@middleware/helpers/middleware-error-handler';
import { wrapRes } from '@middleware/helpers/middleware-response-wrapper';
diff --git a/src/middleware/routes/api-user-roles.ts b/src/middleware/routes/api-user-roles.ts
index c2ead911..ecc9eb97 100644
--- a/src/middleware/routes/api-user-roles.ts
+++ b/src/middleware/routes/api-user-roles.ts
@@ -1,8 +1,12 @@
+/**
+ * @module
+ */
+
import { Router, Request, Response, NextFunction } from 'express';
import getLogger from '@commons/logger';
import { getFromDB } from '@database/api';
import { IUserRole, COLLECTION_NAMES } from '@database/models';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import getMiddlewareErrorHandler from '@middleware/helpers/middleware-error-handler';
import { wrapRes } from '@middleware/helpers/middleware-response-wrapper';
diff --git a/src/middleware/routes/api-users.ts b/src/middleware/routes/api-users.ts
index be790a9d..e0540690 100644
--- a/src/middleware/routes/api-users.ts
+++ b/src/middleware/routes/api-users.ts
@@ -1,10 +1,14 @@
+/**
+ * @module
+ */
+
import { Router, Request, Response, NextFunction } from 'express';
import getLogger from '@commons/logger';
import { saveToDB, getFromDB, updateOneModelInDB, deleteFromDB } from '@database/api';
import { authMiddlewareFn, hashPassword } from '@middleware/features/auth';
import { UserModel, IUser, IProduct, UserRoleModel, IUserRole, COLLECTION_NAMES, Schema } from '@database/models';
import sendMail, { EMAIL_TYPES } from '@middleware/helpers/mailer';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import getMiddlewareErrorHandler from '@middleware/helpers/middleware-error-handler';
import { wrapRes } from '@middleware/helpers/middleware-response-wrapper';
import { dotEnv } from '@commons/dotEnvLoader';
diff --git a/test/e2e/cypress/integration/account.spec.ts b/test/e2e/cypress/integration/account.spec.ts
index 71dbc57d..8a01370f 100644
--- a/test/e2e/cypress/integration/account.spec.ts
+++ b/test/e2e/cypress/integration/account.spec.ts
@@ -1,7 +1,7 @@
import { cy, Cypress, it, describe, context, beforeEach, expect } from 'local-cypress';
import type { TUserPublic } from '@database/models';
import { ROUTES } from '@frontend/components/pages/_routes';
-import { HTTP_STATUS_CODE, TE2EUser } from '@src/types';
+import { HTTP_STATUS_CODE, TE2EUser } from '@commons/types';
import { makeCyDataSelector } from '../synchronous-helpers';
const ACCOUNT_TEST_USER: TE2EUser = Object.freeze({
diff --git a/test/e2e/cypress/integration/login.spec.ts b/test/e2e/cypress/integration/login.spec.ts
index 9da10f46..7bbcee03 100644
--- a/test/e2e/cypress/integration/login.spec.ts
+++ b/test/e2e/cypress/integration/login.spec.ts
@@ -1,6 +1,6 @@
import { cy, describe, beforeEach, it, expect } from 'local-cypress';
import { ROUTES } from '@frontend/components/pages/_routes';
-import { HTTP_STATUS_CODE, TE2EUser } from '@src/types';
+import { HTTP_STATUS_CODE, TE2EUser } from '@commons/types';
import { makeCyDataSelector } from '../synchronous-helpers';
import * as users from '@database/populate/initialData/users.json';
diff --git a/test/e2e/cypress/integration/order.spec.ts b/test/e2e/cypress/integration/order.spec.ts
index 9b51dd05..b7957cc2 100644
--- a/test/e2e/cypress/integration/order.spec.ts
+++ b/test/e2e/cypress/integration/order.spec.ts
@@ -1,5 +1,5 @@
import { beforeEach, cy, describe, expect, it } from 'local-cypress';
-import { TE2EUser, HTTP_STATUS_CODE } from '@src/types';
+import { TE2EUser, HTTP_STATUS_CODE } from '@commons/types';
import { ROUTES } from '@frontend/components/pages/_routes';
import { makeCyDataSelector } from '../synchronous-helpers';
import * as users from '@database/populate/initialData/users.json';
diff --git a/test/e2e/cypress/integration/product-filters.spec.ts b/test/e2e/cypress/integration/product-filters.spec.ts
index c332f70c..77836756 100644
--- a/test/e2e/cypress/integration/product-filters.spec.ts
+++ b/test/e2e/cypress/integration/product-filters.spec.ts
@@ -1,7 +1,7 @@
import { describe, it, cy, expect } from 'local-cypress';
import { ROUTES } from '@frontend/components/pages/_routes';
import { makeCyDataSelector } from '../synchronous-helpers';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
function assertSearchParamsCount(expectedCount: number) {
cy.location('search').should((search) => {
diff --git a/test/e2e/cypress/integration/product-form.spec.ts b/test/e2e/cypress/integration/product-form.spec.ts
index 4f072cd1..f6c261b8 100644
--- a/test/e2e/cypress/integration/product-form.spec.ts
+++ b/test/e2e/cypress/integration/product-form.spec.ts
@@ -1,7 +1,7 @@
import { describe, it, cy, beforeEach, context, expect, after } from 'local-cypress';
import { ROUTES } from '@frontend/components/pages/_routes';
import { makeCyDataSelector } from '../synchronous-helpers';
-import { TE2EUser, HTTP_STATUS_CODE } from '@src/types';
+import { TE2EUser, HTTP_STATUS_CODE } from '@commons/types';
import * as users from '@database/populate/initialData/users.json';
const exampleSellerUser = (users as TE2EUser[])[1];
diff --git a/test/e2e/cypress/integration/register.spec.ts b/test/e2e/cypress/integration/register.spec.ts
index 2675cf6d..79bd79d2 100644
--- a/test/e2e/cypress/integration/register.spec.ts
+++ b/test/e2e/cypress/integration/register.spec.ts
@@ -1,6 +1,6 @@
import { cy, describe, it, beforeEach, expect } from 'local-cypress';
import { ROUTES } from '@frontend/components/pages/_routes';
-import { HTTP_STATUS_CODE, TE2EUser } from '@src/types';
+import { HTTP_STATUS_CODE, TE2EUser } from '@commons/types';
import { makeCyDataSelector } from '../synchronous-helpers';
describe('#register', () => {
diff --git a/test/e2e/cypress/support/index.ts b/test/e2e/cypress/support/index.ts
index e80640fe..e98d5e4e 100644
--- a/test/e2e/cypress/support/index.ts
+++ b/test/e2e/cypress/support/index.ts
@@ -1,7 +1,7 @@
///
import { TMessage } from './email-commands';
-import type { TE2EUser, IUserCart } from '@src/types';
+import type { TE2EUser, IUserCart } from '@commons/types';
import type { TUserPublic, IUser, TProductPublic } from '@database/models';
import type { HeadersInit } from 'node-fetch';
diff --git a/test/e2e/cypress/support/misc-commands.ts b/test/e2e/cypress/support/misc-commands.ts
index 4e5ffe0b..b4b09151 100644
--- a/test/e2e/cypress/support/misc-commands.ts
+++ b/test/e2e/cypress/support/misc-commands.ts
@@ -1,6 +1,6 @@
import { cy, Cypress, expect } from 'local-cypress';
import { ROUTES } from '@frontend/components/pages/_routes';
-import { TE2E, IUserCart, HTTP_STATUS_CODE } from '@src/types';
+import { TE2E, IUserCart, HTTP_STATUS_CODE } from '@commons/types';
Cypress.Commands.add('getFromStorage', (key) => {
return cy.window().then((window) => JSON.parse(window.localStorage.getItem(key) as string));
diff --git a/test/e2e/cypress/support/user-commands.ts b/test/e2e/cypress/support/user-commands.ts
index 3273e577..a94ec812 100644
--- a/test/e2e/cypress/support/user-commands.ts
+++ b/test/e2e/cypress/support/user-commands.ts
@@ -1,6 +1,6 @@
import { cy, Cypress, expect } from 'local-cypress';
import { ROUTES } from '@frontend/components/pages/_routes';
-import type { TE2E } from '@src/types';
+import type { TE2E } from '@commons/types';
import type { TUserPublic } from '@database/models';
import { makeCyDataSelector } from '../synchronous-helpers';
diff --git a/test/unit/middleware/features/auth.spec.ts b/test/unit/middleware/features/auth.spec.ts
index 93144613..f5bde7f3 100644
--- a/test/unit/middleware/features/auth.spec.ts
+++ b/test/unit/middleware/features/auth.spec.ts
@@ -4,7 +4,7 @@ mockAndRequireDBModelsModules();
import { getResMock, TJestMock } from '@unitTests/inline-mocks';
import { IUser, COLLECTION_NAMES } from '@database/models';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import getType from 'jest-get-type';
const { getFromDB: getFromDBMock } = mockAndRequireModule('src/database/api');
diff --git a/test/unit/middleware/middleware-index.spec.ts b/test/unit/middleware/middleware-index.spec.ts
index 666106b6..c8ef150d 100644
--- a/test/unit/middleware/middleware-index.spec.ts
+++ b/test/unit/middleware/middleware-index.spec.ts
@@ -1,6 +1,6 @@
import { getRootRelativePath, mockAndRequireModule } from '@unitTests/utils';
import type { TJestMock } from '@unitTests/inline-mocks';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
const globMock: TJestMock = jest.requireActual(getRootRelativePath('__mocks__/glob'));
const { json: expressJSONMock } = jest.requireActual(getRootRelativePath('__mocks__/express'));
diff --git a/test/unit/middleware/routes/api-product-categories.spec.ts b/test/unit/middleware/routes/api-product-categories.spec.ts
index 7e9584f5..58fc88ea 100644
--- a/test/unit/middleware/routes/api-product-categories.spec.ts
+++ b/test/unit/middleware/routes/api-product-categories.spec.ts
@@ -3,7 +3,7 @@ import { mockAndRequireModule, findAssociatedSrcModulePath, mockAndRequireDBMode
mockAndRequireDBModelsModules();
import { getResMock, TJestMock } from '@unitTests/inline-mocks';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import { COLLECTION_NAMES } from '@database/models';
const { getFromDB } = mockAndRequireModule('src/database/api');
diff --git a/test/unit/middleware/routes/api-products.spec.ts b/test/unit/middleware/routes/api-products.spec.ts
index 22f6bceb..298d51d6 100644
--- a/test/unit/middleware/routes/api-products.spec.ts
+++ b/test/unit/middleware/routes/api-products.spec.ts
@@ -2,7 +2,7 @@ import { findAssociatedSrcModulePath, mockAndRequireModule, mockAndRequireDBMode
mockAndRequireDBModelsModules();
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import { getNextFnMock, getResMock, TJestMock } from '@unitTests/inline-mocks';
import { COLLECTION_NAMES, USER_ROLES_MAP } from '@database/models';
diff --git a/test/unit/middleware/routes/api-user-roles.spec.ts b/test/unit/middleware/routes/api-user-roles.spec.ts
index ed7a6e05..54f4ef3f 100644
--- a/test/unit/middleware/routes/api-user-roles.spec.ts
+++ b/test/unit/middleware/routes/api-user-roles.spec.ts
@@ -3,7 +3,7 @@ import { findAssociatedSrcModulePath, mockAndRequireModule, mockAndRequireDBMode
mockAndRequireDBModelsModules();
import { getResMock, TJestMock } from '@unitTests/inline-mocks';
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import { COLLECTION_NAMES } from '@database/models';
const { Router, _router } = mockAndRequireModule('express');
diff --git a/test/unit/middleware/routes/api-users.spec.ts b/test/unit/middleware/routes/api-users.spec.ts
index 3f7bfad9..8a16b4ab 100644
--- a/test/unit/middleware/routes/api-users.spec.ts
+++ b/test/unit/middleware/routes/api-users.spec.ts
@@ -7,7 +7,7 @@ const {
} = mockAndRequireModule('mongoose');
mockAndRequireDBModelsModules();
-import { HTTP_STATUS_CODE } from '@src/types';
+import { HTTP_STATUS_CODE } from '@commons/types';
import { getResMock, getNextFnMock, TJestMock } from '@unitTests/inline-mocks';
import { COLLECTION_NAMES } from '@database/models';
diff --git a/tsconfig.frontend.json b/tsconfig.frontend.json
index 8fac5fc5..728bbac1 100644
--- a/tsconfig.frontend.json
+++ b/tsconfig.frontend.json
@@ -1,6 +1,6 @@
{
"extends": "./tsconfig.json",
- "include": ["./src/frontend/**/*.ts"],
+ "include": ["./src/frontend/**/*.ts?"],
"exclude": ["./src/**/__mocks__"],
"compilerOptions": {
"module": "ES2020",
diff --git a/tsconfig.typedoc.json b/tsconfig.typedoc.json
new file mode 100644
index 00000000..8f8bbad4
--- /dev/null
+++ b/tsconfig.typedoc.json
@@ -0,0 +1,11 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["./src/**/*.ts", "./src/**/*.tsx", "./src/**/*.js", "./src/**/*.jsx", "./commons/**/*.ts"],
+ "files": ["./src/augmentations.d.ts", "./src/database/populate/populate.ts"],
+ "compilerOptions": {
+ "outDir": "_tmp-compiled-scripts-for-docs",
+ "skipLibCheck": true,
+ "allowJs": true,
+ "jsx": "react"
+ }
+}
diff --git a/typedoc.json b/typedoc.json
new file mode 100644
index 00000000..c5b3d63d
--- /dev/null
+++ b/typedoc.json
@@ -0,0 +1,8 @@
+{
+ "tsconfig": "./tsconfig.typedoc.json",
+ "entryPointStrategy": "expand",
+ "excludeInternal": true,
+ "excludeExternals": true,
+ "exclude": ["./src/**/__mocks__/**", "./src/frontend/assets/**"],
+ "readme": "none"
+}