Compare commits

..

10 Commits

Author SHA1 Message Date
fa44cee781 Release 1.96.0 (#590) 2021-12-27 21:08:33 +01:00
db1d474ddf Feature/more discreet data provider warning (#589)
* Upgrade http-status-codes to version 2.2.0

* Make the data provider warning more discreet

* Update changelog
2021-12-27 12:14:41 +01:00
994275e093 Feature/upgrade angular 3rd party dependencies (#588)
* Upgrade angular 3rd party dependencies
  * ngx-device-detector
  * ngx-markdown
  * ngx-stripe

* Update changelog
2021-12-26 21:58:56 +01:00
ee397c8047 Bugfix/fix file type detection for import (#587)
* Fix file type detection ("application/vnd.ms-excel" instead of "text/csv")

* Update changelog
2021-12-26 20:54:53 +01:00
7203939c42 Feature/upgrade prisma to version 3.7.0 (#586)
* Upgrade prisma from version 3.6.0 to 3.7.0

* Update changelog
2021-12-26 17:30:26 +01:00
9725f16c81 Clean up schema.prisma (#584) 2021-12-26 14:33:18 +01:00
bb8b1e4f43 Release 1.95.0 (#583) 2021-12-26 10:14:13 +01:00
9d3610331a Add guard (#582) 2021-12-26 10:07:51 +01:00
0043b44670 Feature/improve data gathering for currencies (#581)
* Improve data gathering for currencies, add warning if it fails

* Update changelog
2021-12-26 09:15:10 +01:00
bbc4e64cb4 Bugfix/filter currencies with null value (#579)
* Filter currencies with null value

* Update changelog
2021-12-25 17:08:56 +01:00
16 changed files with 196 additions and 149 deletions

View File

@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.96.0 - 27.12.2021
### Changed
- Made the data provider warning more discreet
- Upgraded `http-status-codes` from version `2.1.4` to `2.2.0`
- Upgraded `ngx-device-detector` from version `2.1.1` to `3.0.0`
- Upgraded `ngx-markdown` from version `12.0.1` to `13.0.0`
- Upgraded `ngx-stripe` from version `12.0.2` to `13.0.0`
- Upgraded `prisma` from version `3.6.0` to `3.7.0`
### Fixed
- Fixed the file type detection in the import functionality for transactions
## 1.95.0 - 26.12.2021
### Added
- Added a warning to the log if the data gathering fails
### Fixed
- Filtered potential `null` currencies
- Improved the 7d data gathering optimization for currencies
## 1.94.0 - 25.12.2021
### Added

View File

@ -51,7 +51,7 @@ export class PortfolioController {
@Get('investments')
@UseGuards(AuthGuard('jwt'))
public async findAll(
@Headers('impersonation-id') impersonationId,
@Headers('impersonation-id') impersonationId: string,
@Res() res: Response
): Promise<InvestmentItem[]> {
if (
@ -87,7 +87,7 @@ export class PortfolioController {
@Get('chart')
@UseGuards(AuthGuard('jwt'))
public async getChart(
@Headers('impersonation-id') impersonationId,
@Headers('impersonation-id') impersonationId: string,
@Query('range') range,
@Res() res: Response
): Promise<PortfolioChart> {
@ -98,18 +98,14 @@ export class PortfolioController {
let chartData = historicalDataContainer.items;
let hasNullValue = false;
let hasError = false;
chartData.forEach((chartDataItem) => {
if (hasNotDefinedValuesInObject(chartDataItem)) {
hasNullValue = true;
hasError = true;
}
});
if (hasNullValue) {
res.status(StatusCodes.ACCEPTED);
}
if (
impersonationId ||
this.userService.isRestrictedView(this.request.user)
@ -131,6 +127,7 @@ export class PortfolioController {
}
return <any>res.json({
hasError,
chart: chartData,
isAllTimeHigh: historicalDataContainer.isAllTimeHigh,
isAllTimeLow: historicalDataContainer.isAllTimeLow
@ -140,7 +137,7 @@ export class PortfolioController {
@Get('details')
@UseGuards(AuthGuard('jwt'))
public async getDetails(
@Headers('impersonation-id') impersonationId,
@Headers('impersonation-id') impersonationId: string,
@Query('range') range,
@Res() res: Response
): Promise<PortfolioDetails> {
@ -152,6 +149,8 @@ export class PortfolioController {
return <any>res.json({ accounts: {}, holdings: {} });
}
let hasError = false;
const { accounts, holdings, hasErrors } =
await this.portfolioService.getDetails(
impersonationId,
@ -160,7 +159,7 @@ export class PortfolioController {
);
if (hasErrors || hasNotDefinedValuesInObject(holdings)) {
res.status(StatusCodes.ACCEPTED);
hasError = true;
}
if (
@ -198,43 +197,38 @@ export class PortfolioController {
}
}
return <any>res.json({ accounts, holdings });
return <any>res.json({ accounts, hasError, holdings });
}
@Get('performance')
@UseGuards(AuthGuard('jwt'))
public async getPerformance(
@Headers('impersonation-id') impersonationId,
@Headers('impersonation-id') impersonationId: string,
@Query('range') range,
@Res() res: Response
): Promise<PortfolioPerformance> {
): Promise<{ hasErrors: boolean; performance: PortfolioPerformance }> {
const performanceInformation = await this.portfolioService.getPerformance(
impersonationId,
range
);
if (performanceInformation?.hasErrors) {
res.status(StatusCodes.ACCEPTED);
}
let performance = performanceInformation.performance;
if (
impersonationId ||
this.userService.isRestrictedView(this.request.user)
) {
performance = nullifyValuesInObject(performance, [
'currentGrossPerformance',
'currentValue'
]);
performanceInformation.performance = nullifyValuesInObject(
performanceInformation.performance,
['currentGrossPerformance', 'currentValue']
);
}
return <any>res.json(performance);
return <any>res.json(performanceInformation);
}
@Get('positions')
@UseGuards(AuthGuard('jwt'))
public async getPositions(
@Headers('impersonation-id') impersonationId,
@Headers('impersonation-id') impersonationId: string,
@Query('range') range,
@Res() res: Response
): Promise<PortfolioPositions> {
@ -243,10 +237,6 @@ export class PortfolioController {
range
);
if (result?.hasErrors) {
res.status(StatusCodes.ACCEPTED);
}
if (
impersonationId ||
this.userService.isRestrictedView(this.request.user)
@ -353,7 +343,7 @@ export class PortfolioController {
@Get('position/:symbol')
@UseGuards(AuthGuard('jwt'))
public async getPosition(
@Headers('impersonation-id') impersonationId,
@Headers('impersonation-id') impersonationId: string,
@Param('symbol') symbol
): Promise<PortfolioPositionDetail> {
let position = await this.portfolioService.getPosition(
@ -387,7 +377,7 @@ export class PortfolioController {
@Get('report')
@UseGuards(AuthGuard('jwt'))
public async getReport(
@Headers('impersonation-id') impersonationId,
@Headers('impersonation-id') impersonationId: string,
@Res() res: Response
): Promise<PortfolioReport> {
if (

View File

@ -242,7 +242,7 @@ export class DataGatheringService {
try {
currentData[symbol] = await dataEnhancer.enhance({
response,
symbol: symbolMapping[dataEnhancer.getName()] ?? symbol
symbol: symbolMapping?.[dataEnhancer.getName()] ?? symbol
});
} catch (error) {
Logger.error(`Failed to enhance data for symbol ${symbol}`, error);
@ -334,16 +334,25 @@ export class DataGatheringService {
?.marketPrice;
}
try {
await this.prismaService.marketData.create({
data: {
dataSource,
symbol,
date: currentDate,
marketPrice: lastMarketPrice
}
});
} catch {}
if (lastMarketPrice) {
try {
await this.prismaService.marketData.create({
data: {
dataSource,
symbol,
date: currentDate,
marketPrice: lastMarketPrice
}
});
} catch {}
} else {
Logger.warn(
`Failed to gather data for symbol ${symbol} at ${format(
currentDate,
DATE_FORMAT
)}.`
);
}
// Count month one up for iteration
currentDate = new Date(
@ -492,8 +501,8 @@ export class DataGatheringService {
}
})
)
.filter((symbolProfile) => {
return symbolsToGather.includes(symbolProfile.symbol);
.filter(({ symbol }) => {
return symbolsToGather.includes(symbol);
})
.map((symbolProfile) => {
return {
@ -504,6 +513,9 @@ export class DataGatheringService {
const currencyPairsToGather = this.exchangeRateDataService
.getCurrencyPairs()
.filter(({ symbol }) => {
return symbolsToGather.includes(symbol);
})
.map(({ dataSource, symbol }) => {
return {
dataSource,

View File

@ -157,7 +157,12 @@ export class ExchangeRateDataService {
await this.prismaService.account.findMany({
distinct: ['currency'],
orderBy: [{ currency: 'asc' }],
select: { currency: true }
select: { currency: true },
where: {
currency: {
not: null
}
}
})
).forEach((account) => {
currencies.push(account.currency);
@ -167,7 +172,12 @@ export class ExchangeRateDataService {
await this.prismaService.settings.findMany({
distinct: ['currency'],
orderBy: [{ currency: 'asc' }],
select: { currency: true }
select: { currency: true },
where: {
currency: {
not: null
}
}
})
).forEach((userSettings) => {
currencies.push(userSettings.currency);
@ -177,7 +187,12 @@ export class ExchangeRateDataService {
await this.prismaService.symbolProfile.findMany({
distinct: ['currency'],
orderBy: [{ currency: 'asc' }],
select: { currency: true }
select: { currency: true },
where: {
currency: {
not: null
}
}
})
).forEach((symbolProfile) => {
currencies.push(symbolProfile.currency);

View File

@ -29,6 +29,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
{ label: 'Max', value: 'max' }
];
public deviceType: string;
public hasError: boolean;
public hasImpersonationId: boolean;
public historicalDataItems: LineChartItem[];
public isAllTimeHigh: boolean;
@ -116,7 +117,8 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
.fetchPortfolioPerformance({ range: this.dateRange })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => {
this.performance = response;
this.hasError = response.hasErrors;
this.performance = response.performance;
this.isLoadingPerformance = false;
this.changeDetectorRef.markForCheck();

View File

@ -1,15 +1,5 @@
<div
class="
align-items-center
container
d-flex
flex-column
h-100
justify-content-center
overview
p-0
position-relative
"
class="align-items-center container d-flex flex-column h-100 justify-content-center overview p-0 position-relative"
>
<div class="row w-100">
<div class="chart-container col">
@ -37,6 +27,8 @@
<gf-portfolio-performance
class="pb-4"
[baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="deviceType"
[hasError]="hasError"
[isAllTimeHigh]="isAllTimeHigh"
[isAllTimeLow]="isAllTimeLow"
[isLoading]="isLoadingPerformance"

View File

@ -1,12 +1,15 @@
<div class="container p-0">
<div
class="no-gutters row"
[ngClass]="{
'text-danger': isAllTimeLow,
'text-success': isAllTimeHigh
}"
>
<div class="flex-grow-1"></div>
<div class="no-gutters row">
<div
class="flex-grow-1 status text-muted text-right"
[title]="
hasError
? 'Sorry! Our data provider partner is experiencing the hiccups.'
: ''
"
>
<ion-icon *ngIf="hasError" name="alert-circle-outline"></ion-icon>
</div>
<div *ngIf="isLoading" class="align-items-center d-flex">
<ngx-skeleton-loader
animation="pulse"
@ -20,6 +23,10 @@
<div
class="display-4 font-weight-bold m-0 text-center value-container"
[hidden]="isLoading"
[ngClass]="{
'text-danger': isAllTimeLow,
'text-success': isAllTimeHigh
}"
>
<span #value id="value"></span>
</div>

View File

@ -1,6 +1,10 @@
:host {
display: block;
.status {
font-size: 1.33rem;
}
.value-container {
#value {
font-variant-numeric: tabular-nums;

View File

@ -19,6 +19,8 @@ import { isNumber } from 'lodash';
})
export class PortfolioPerformanceComponent implements OnChanges, OnInit {
@Input() baseCurrency: string;
@Input() deviceType: string;
@Input() hasError: boolean;
@Input() isAllTimeHigh: boolean;
@Input() isAllTimeLow: boolean;
@Input() isLoading: boolean;
@ -44,7 +46,11 @@ export class PortfolioPerformanceComponent implements OnChanges, OnInit {
this.unit = this.baseCurrency;
new CountUp('value', this.performance?.currentValue, {
decimalPlaces: 2,
decimalPlaces:
this.deviceType === 'mobile' &&
this.performance?.currentValue >= 100000
? 0
: 2,
duration: 1,
separator: `'`
}).start();

View File

@ -4,8 +4,7 @@ import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
HttpResponse
HttpRequest
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import {
@ -43,26 +42,6 @@ export class HttpResponseInterceptor implements HttpInterceptor {
): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
tap((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
if (event.status === StatusCodes.ACCEPTED) {
if (!this.snackBarRef) {
this.snackBarRef = this.snackBar.open(
'Sorry! Our data provider partner is experiencing a mild case of the hiccups ;(',
'Try again?',
{ duration: 6000 }
);
this.snackBarRef.afterDismissed().subscribe(() => {
this.snackBarRef = undefined;
});
this.snackBarRef.onAction().subscribe(() => {
window.location.reload();
});
}
}
}
return event;
}),
catchError((error: HttpErrorResponse) => {

View File

@ -188,7 +188,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
const fileContent = readerEvent.target.result as string;
try {
if (file.type === 'application/json') {
if (file.name.endsWith('.json')) {
const content = JSON.parse(fileContent);
if (!isArray(content.orders)) {
@ -203,11 +203,12 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
this.handleImportSuccess();
} catch (error) {
console.error(error);
this.handleImportError({ error, orders: content.orders });
}
return;
} else if (file.type === 'text/csv') {
} else if (file.name.endsWith('.csv')) {
try {
await this.importTransactionsService.importCsv({
fileContent,
@ -217,6 +218,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
this.handleImportSuccess();
} catch (error) {
console.error(error);
this.handleImportError({
error: {
error: { message: error?.error?.message ?? [error?.message] }
@ -230,6 +232,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
throw new Error();
} catch (error) {
console.error(error);
this.handleImportError({
error: { error: { message: ['Unexpected format'] } },
orders: []

View File

@ -181,7 +181,10 @@ export class DataService {
}
public fetchPortfolioPerformance(aParams: { [param: string]: any }) {
return this.http.get<PortfolioPerformance>('/api/portfolio/performance', {
return this.http.get<{
hasErrors: boolean;
performance: PortfolioPerformance;
}>('/api/portfolio/performance', {
params: aParams
});
}

View File

@ -1,6 +1,7 @@
import { HistoricalDataItem } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-position-detail.interface';
export interface PortfolioChart {
hasError: boolean;
isAllTimeHigh: boolean;
isAllTimeLow: boolean;
chart: HistoricalDataItem[];

View File

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "1.94.0",
"version": "1.96.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"scripts": {
@ -69,7 +69,7 @@
"@nestjs/schedule": "1.0.2",
"@nestjs/serve-static": "2.2.2",
"@nrwl/angular": "13.3.0",
"@prisma/client": "3.6.0",
"@prisma/client": "3.7.0",
"@simplewebauthn/browser": "4.1.0",
"@simplewebauthn/server": "4.1.0",
"@simplewebauthn/typescript-types": "4.0.0",
@ -94,18 +94,18 @@
"cryptocurrencies": "7.0.0",
"date-fns": "2.22.1",
"envalid": "7.2.1",
"http-status-codes": "2.1.4",
"http-status-codes": "2.2.0",
"ionicons": "5.5.1",
"lodash": "4.17.21",
"ngx-device-detector": "2.1.1",
"ngx-markdown": "12.0.1",
"ngx-device-detector": "3.0.0",
"ngx-markdown": "13.0.0",
"ngx-skeleton-loader": "2.9.1",
"ngx-stripe": "12.0.2",
"ngx-stripe": "13.0.0",
"papaparse": "5.3.1",
"passport": "0.4.1",
"passport-google-oauth20": "2.0.0",
"passport-jwt": "4.0.0",
"prisma": "3.6.0",
"prisma": "3.7.0",
"reflect-metadata": "0.1.13",
"round-to": "5.0.0",
"rxjs": "7.4.0",

View File

@ -1,6 +1,3 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")

104
yarn.lock
View File

@ -2854,22 +2854,22 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.1.tgz#728ecd95ab207aab8a9a4e421f0422db329232be"
integrity sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==
"@prisma/client@3.6.0":
version "3.6.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.6.0.tgz#68a60cd4c73a369b11f72e173e86fd6789939293"
integrity sha512-ycSGY9EZGROtje0iCNsgC5Zqi/ttX2sO7BNMYaLsUMiTlf3F69ZPH+08pRo0hrDfkZzyimXYqeXJlaoYDH1w7A==
"@prisma/client@3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.7.0.tgz#9cafc105f12635c95e9b7e7b18e8fbf52cf3f18a"
integrity sha512-fUJMvBOX5C7JPc0e3CJD6Gbelbu4dMJB4ScYpiht8HMUnRShw20ULOipTopjNtl6ekHQJ4muI7pXlQxWS9nMbw==
dependencies:
"@prisma/engines-version" "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727"
"@prisma/engines-version" "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f"
"@prisma/engines-version@3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727":
version "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#25aa447776849a774885866b998732b37ec4f4f5"
integrity sha512-vtoO2ys6mSfc8ONTWdcYztKN3GBU1tcKBj0aXObyjzSuGwHFcM/pEA0xF+n1W4/0TAJgfoPX2khNEit6g0jtNA==
"@prisma/engines-version@3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f":
version "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f.tgz#055f36ac8b06c301332c14963cd0d6c795942c90"
integrity sha512-+qx2b+HK7BKF4VCa0LZ/t1QCXsu6SmvhUQyJkOD2aPpmOzket4fEnSKQZSB0i5tl7rwCDsvAiSeK8o7rf+yvwg==
"@prisma/engines@3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727":
version "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#c68ede6aeffa9ef7743a32cfa6daf9172a4e15b3"
integrity sha512-dRClHS7DsTVchDKzeG72OaEyeDskCv91pnZ72Fftn0mp4BkUvX2LvWup65hCNzwwQm5IDd6A88APldKDnMiEMA==
"@prisma/engines@3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f":
version "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f.tgz#12f28d5b78519fbd84c89a5bdff457ff5095e7a2"
integrity sha512-W549ub5NlgexNhR8EFstA/UwAWq3Zq0w9aNkraqsozVCt2CsX+lK4TK7IW5OZVSnxHwRjrgEAt3r9yPy8nZQRg==
"@samverschueren/stream-to-observable@^0.3.0":
version "0.3.1"
@ -6688,11 +6688,16 @@ commander@^5.1.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
commander@^6.0.0, commander@^6.2.1:
commander@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
commander@^8.0.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
common-tags@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@ -7799,7 +7804,7 @@ emoji-regex@^8.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
emoji-toolkit@^6.5.0:
emoji-toolkit@^6.6.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/emoji-toolkit/-/emoji-toolkit-6.6.0.tgz#e7287c43a96f940ec4c5428cd7100a40e57518f1"
integrity sha512-pEu0kow2p1N8zCKnn/L6H0F3rWUBB3P3hVjr/O5yl1fK7N9jU4vO4G7EFapC5Y3XwZLUCY0FZbOPyTkH+4V2eQ==
@ -10027,10 +10032,10 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
http-status-codes@2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.1.4.tgz#453d99b4bd9424254c4f6a9a3a03715923052798"
integrity sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg==
http-status-codes@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.2.0.tgz#bb2efe63d941dfc2be18e15f703da525169622be"
integrity sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==
https-browserify@^1.0.0:
version "1.0.0"
@ -11859,12 +11864,12 @@ karma-source-map-support@1.4.0:
dependencies:
source-map-support "^0.5.5"
katex@^0.13.0:
version "0.13.18"
resolved "https://registry.yarnpkg.com/katex/-/katex-0.13.18.tgz#ba89e8e4b70cc2325e25e019a62b9fe71e5c2931"
integrity sha512-a3dC4NSVSDU3O1WZbTnOiA8rVNJ2lSiomOl0kmckCIGObccIHXof7gAseIY0o1gjEspe+34ZeSEX2D1ChFKIvA==
katex@^0.15.1:
version "0.15.1"
resolved "https://registry.yarnpkg.com/katex/-/katex-0.15.1.tgz#cf4ce2fa1257c3279cc7a7fe0c8d1fab40800893"
integrity sha512-KIk+gizli0gl1XaJlCYS8/donGMbzXYTka6BbH3AgvDJTOwyDY4hJ+YmzJ1F0y/3XzX5B9ED8AqB2Hmn2AZ0uA==
dependencies:
commander "^6.0.0"
commander "^8.0.0"
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
@ -12821,24 +12826,24 @@ nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0:
resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61"
integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==
ngx-device-detector@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ngx-device-detector/-/ngx-device-detector-2.1.1.tgz#a22a9477f382d02edf28786c5609878a57d2834f"
integrity sha512-eTuQLAmc2XRRbxDnO9h1QVV0piSyPjstXT5G8fo1rvXy7Ly3MAiniEM2WvTiN7FjtY/VdhEeuBmu/ErSm5cLJg==
ngx-device-detector@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ngx-device-detector/-/ngx-device-detector-3.0.0.tgz#9c5b1db66e03837d5de0e93fe4a1de93948c9c81"
integrity sha512-mzegvxnNTDkHTxh+UeWnCUgZ91/XDOcN2kj8aCupvA7wNgDc/NZ0L90feKJsc+wES7IWq0/DIIKq2F732WOkfw==
dependencies:
tslib "^2.0.0"
ngx-markdown@12.0.1:
version "12.0.1"
resolved "https://registry.yarnpkg.com/ngx-markdown/-/ngx-markdown-12.0.1.tgz#94345e99176533c17396f93e97ff5dc172d8ebcc"
integrity sha512-vMp9SyqmVQZCX374MiCV4sRR1SIv5m3xR2HZ39b3+6/BGjAb46mb4wRXKdIxYUoPba7NYZ8GAt5moUCyVZcCyA==
ngx-markdown@13.0.0:
version "13.0.0"
resolved "https://registry.yarnpkg.com/ngx-markdown/-/ngx-markdown-13.0.0.tgz#07c9ef46db6827290fc533c0ee64d3856e964bfd"
integrity sha512-XIFCoqffGUHoc8mpHphVskFBHck6hUBocyGVHNBznk7dzHdy6+Ir08jECDQa6xhsoU4dTDgo9aofjK+yvzGIXw==
dependencies:
"@types/marked" "^2.0.0"
emoji-toolkit "^6.5.0"
katex "^0.13.0"
emoji-toolkit "^6.6.0"
katex "^0.15.1"
marked "^2.0.0"
prismjs "^1.23.0"
tslib "^2.1.0"
prismjs "^1.25.0"
tslib "^2.3.0"
ngx-skeleton-loader@2.9.1:
version "2.9.1"
@ -12848,12 +12853,12 @@ ngx-skeleton-loader@2.9.1:
perf-marks "^1.13.4"
tslib "^1.10.0"
ngx-stripe@12.0.2:
version "12.0.2"
resolved "https://registry.yarnpkg.com/ngx-stripe/-/ngx-stripe-12.0.2.tgz#b250acc2a08dc96dac035fc0a67b4a8cbeca3efb"
integrity sha512-/arfIi996yv3EpzqjYsb20TUdQ9t+GVMNVIx1mdsiWcpiNjL36tO3lG45T0hyiBJNAds87Ag40Fm8PfsuHFCUw==
ngx-stripe@13.0.0:
version "13.0.0"
resolved "https://registry.yarnpkg.com/ngx-stripe/-/ngx-stripe-13.0.0.tgz#d5ed50590447aa74012de4e75ac9bcdafc68b1c8"
integrity sha512-SImKvoC/mZZrtzh2UUmxFdkqMLKX2y+BtcvMAPdHD4D7miXWEjCTZeXt8h85mcfy7y1NKKwIipH4CSr9eBzZ4w==
dependencies:
tslib "^2.1.0"
tslib "^2.3.0"
nice-napi@^1.0.2:
version "1.0.2"
@ -14436,18 +14441,23 @@ pretty-hrtime@^1.0.3:
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
prisma@3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.6.0.tgz#99532abc02e045e58c6133a19771bdeb28cecdbe"
integrity sha512-6SqgHS/5Rq6HtHjsWsTxlj+ySamGyCLBUQfotc2lStOjPv52IQuDVpp58GieNqc9VnfuFyHUvTZw7aQB+G2fvQ==
prisma@3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.7.0.tgz#9c73eeb2f16f767fdf523d0f4cc4c749734d62e2"
integrity sha512-pzgc95msPLcCHqOli7Hnabu/GRfSGSUWl5s2P6N13T/rgMB+NNeKbxCmzQiZT2yLOeLEPivV6YrW1oeQIwJxcg==
dependencies:
"@prisma/engines" "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727"
"@prisma/engines" "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f"
prismjs@^1.21.0, prismjs@^1.23.0, prismjs@~1.24.0:
prismjs@^1.21.0, prismjs@~1.24.0:
version "1.24.1"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.24.1.tgz#c4d7895c4d6500289482fa8936d9cdd192684036"
integrity sha512-mNPsedLuk90RVJioIky8ANZEwYm5w9LcvCXrxHlwf4fNVSn8jEipMybMkWUyyF0JhnC+C4VcOVSBuHRKs1L5Ow==
prismjs@^1.25.0:
version "1.25.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756"
integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"