Browse Source

Merge branch 'main' into next

pull/6766/merge
Thomas Kaul 14 hours ago
parent
commit
2abba414b0
  1. 18
      CHANGELOG.md
  2. 5
      apps/api/src/app/access/access.controller.ts
  3. 3
      apps/api/src/app/endpoints/public/public.controller.ts
  4. 12
      apps/api/src/app/portfolio/portfolio.controller.ts
  5. 7
      apps/api/src/app/user/user.service.ts
  6. 109
      apps/api/src/assets/cryptocurrencies/cryptocurrencies.json
  7. 7
      apps/api/src/services/data-provider/data-provider.service.ts
  8. 7
      apps/client/src/app/components/admin-overview/admin-overview.component.ts
  9. 5
      apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
  10. 3
      apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts
  11. 7
      apps/client/src/assets/oss-friends.json
  12. 3707
      package-lock.json
  13. 42
      package.json

18
CHANGELOG.md

@ -16,7 +16,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Breaking Change**: The `sslmode=prefer` parameter in `DATABASE_URL` is no longer supported. Please update your environment variables (see `.env`) to use `sslmode=require` if _SSL_ is enabled or remove the `sslmode` parameter entirely if _SSL_ is not used.
## 2.255.0 - 2026-03-20
## Unreleased
### Changed
- Refreshed the cryptocurrencies list
- Upgraded `countup.js` from version `2.9.0` to `2.10.0`
- Upgraded `jsonpath` from version `1.2.1` to `1.3.0`
- Upgraded `nestjs` from version `11.1.14` to `11.1.19`
- Upgraded `Nx` from version `22.6.4` to `22.6.5`
## 2.255.0 - 2026-04-20
### Changed
@ -33,7 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed the missing value column of the accounts table component on mobile
## 2.254.0 - 2026-03-10
## 2.254.0 - 2026-04-10
### Added
@ -51,7 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the style of the activity type component
## 2.253.0 - 2026-03-06
## 2.253.0 - 2026-04-06
### Added
@ -71,7 +81,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed the allocations by ETF provider chart on the allocations page in the _Presenter View_
- Fixed the allocations by platform chart on the allocations page in the _Presenter View_
## 2.252.0 - 2026-03-02
## 2.252.0 - 2026-04-02
### Added

5
apps/api/src/app/access/access.controller.ts

@ -2,6 +2,7 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { CreateAccessDto, UpdateAccessDto } from '@ghostfolio/common/dtos';
import { SubscriptionType } from '@ghostfolio/common/enums';
import { Access } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
@ -75,7 +76,7 @@ export class AccessController {
): Promise<AccessModel> {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic'
this.request.user.subscription.type === SubscriptionType.Basic
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
@ -130,7 +131,7 @@ export class AccessController {
): Promise<AccessModel> {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic'
this.request.user.subscription.type === SubscriptionType.Basic
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),

3
apps/api/src/app/endpoints/public/public.controller.ts

@ -7,6 +7,7 @@ import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interc
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { DEFAULT_CURRENCY } from '@ghostfolio/common/config';
import { SubscriptionType } from '@ghostfolio/common/enums';
import { getSum } from '@ghostfolio/common/helper';
import { PublicPortfolioResponse } from '@ghostfolio/common/interfaces';
import type { RequestWithUser } from '@ghostfolio/common/types';
@ -58,7 +59,7 @@ export class PublicController {
});
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
hasDetails = user.subscription.type === 'Premium';
hasDetails = user.subscription.type === SubscriptionType.Premium;
}
const [

12
apps/api/src/app/portfolio/portfolio.controller.ts

@ -17,6 +17,7 @@ import {
HEADER_KEY_IMPERSONATION,
UNKNOWN_KEY
} from '@ghostfolio/common/config';
import { SubscriptionType } from '@ghostfolio/common/enums';
import {
PortfolioDetails,
PortfolioDividendsResponse,
@ -92,7 +93,8 @@ export class PortfolioController {
let hasError = false;
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
hasDetails = this.request.user.subscription.type === 'Premium';
hasDetails =
this.request.user.subscription.type === SubscriptionType.Premium;
}
const filters = this.apiService.buildFiltersFromQueryParams({
@ -356,7 +358,7 @@ export class PortfolioController {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic'
this.request.user.subscription.type === SubscriptionType.Basic
) {
dividends = dividends.map((item) => {
return nullifyValuesInObject(item, ['investment']);
@ -484,7 +486,7 @@ export class PortfolioController {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic'
this.request.user.subscription.type === SubscriptionType.Basic
) {
investments = investments.map((item) => {
return nullifyValuesInObject(item, ['investment']);
@ -596,7 +598,7 @@ export class PortfolioController {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic'
this.request.user.subscription.type === SubscriptionType.Basic
) {
performanceInformation.chart = performanceInformation.chart.map(
(item) => {
@ -624,7 +626,7 @@ export class PortfolioController {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic'
this.request.user.subscription.type === SubscriptionType.Basic
) {
for (const category of report.xRay.categories) {
category.rules = null;

7
apps/api/src/app/user/user.service.ts

@ -32,6 +32,7 @@ import {
TAG_ID_EXCLUDE_FROM_ANALYSIS,
locale as defaultLocale
} from '@ghostfolio/common/config';
import { SubscriptionType } from '@ghostfolio/common/enums';
import {
User as IUser,
SystemMessage,
@ -156,7 +157,7 @@ export class UserService {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
subscription.type === 'Basic'
subscription.type === SubscriptionType.Basic
) {
tags = [];
}
@ -443,7 +444,7 @@ export class UserService {
createdAt: user.createdAt
});
if (user.subscription?.type === 'Basic') {
if (user.subscription?.type === SubscriptionType.Basic) {
const daysSinceRegistration = differenceInDays(
new Date(),
user.createdAt
@ -485,7 +486,7 @@ export class UserService {
// Reset holdings view mode
user.settings.settings.holdingsViewMode = undefined;
} else if (user.subscription?.type === 'Premium') {
} else if (user.subscription?.type === SubscriptionType.Premium) {
if (!hasRole(user, Role.DEMO)) {
currentPermissions.push(permissions.createApiKey);
currentPermissions.push(permissions.enableDataProviderGhostfolio);

109
apps/api/src/assets/cryptocurrencies/cryptocurrencies.json

@ -40,6 +40,7 @@
"0NE": "Stone",
"0X0": "0x0.ai",
"0X1": "0x1.tools: AI Multi-tool Plaform",
"0X63SPIKE": "Spike",
"0XBTC": "0xBitcoin",
"0XCOCO": "0xCoco",
"0XDEV": "DEVAI",
@ -773,7 +774,7 @@
"ANALY": "Analysoor",
"ANARCHISTS": "Anarchists Prime",
"ANAT": "Anatolia Token",
"ANB": "Angryb",
"ANB": "Ant BlockChain",
"ANC": "Anchor Protocol",
"ANCHOR": "AnchorSwap",
"ANCIENTKING": "Ancient Kingdom",
@ -798,6 +799,7 @@
"ANGLE": "ANGLE",
"ANGO": "Aureus Nummus Gold",
"ANGRYSLERF": "ANGRYSLERF",
"ANGRYTOKEN": "Angryb",
"ANI": "Ani Grok Companion (anicompanion.net)",
"ANIM": "Animalia",
"ANIMA": "Realm Anima",
@ -1047,6 +1049,7 @@
"ARTDRAW": "ArtDraw",
"ARTE": "Artemine",
"ARTEM": "Artem",
"ARTEMIS": "OFFICIAL ARTEMIS",
"ARTEON": "Arteon",
"ARTEQ": "artèQ",
"ARTEX": "Artex",
@ -1120,6 +1123,10 @@
"ASTA": "ASTA",
"ASTER": "Aster",
"ASTERINU": "Aster INU",
"ASTEROID": "ASTEROID",
"ASTEROIDBOT": "Asteroid Bot",
"ASTEROIDCOIN": "ASTEROID",
"ASTEROIDETH": "Asteroid",
"ASTHERUSUSDF": "Astherus USDF",
"ASTO": "Altered State Token",
"ASTON": "Aston",
@ -1564,6 +1571,7 @@
"BANANO": "Banano",
"BANC": "Babes and Nerds",
"BANCA": "BANCA",
"BANCORUSD": "USD Bancor",
"BAND": "Band Protocol",
"BANDEX": "Banana Index",
"BANDIT": "Bandit on Base",
@ -1602,11 +1610,12 @@
"BART": "BarterTrade",
"BARTKRC": "BART Token",
"BARY": "Bary",
"BAS": "BNB Attestation Service",
"BASEAI": "BaseAI",
"BASEBEAR": "BBQ",
"BASECAT": "BASE CAT",
"BASECOIN": "BASECOIN",
"BASED": "Based Money",
"BASED": "Based Token",
"BASEDAI": "BasedAI",
"BASEDALF": "Based Alf",
"BASEDB": "Based Bonk",
@ -1614,12 +1623,13 @@
"BASEDCOPE": "COPE",
"BASEDFINANCE": "Based",
"BASEDHOPPY": "Based Hoppy (basedhoppy.vip)",
"BASEDMONEY": "Based Money",
"BASEDMONEYV1": "Based Money v1",
"BASEDP": "Based Pepe",
"BASEDR": "Based Rabbit",
"BASEDS": "BasedSwap",
"BASEDSB": "Based Street Bets",
"BASEDTURBO": "Based Turbo",
"BASEDV1": "Based Money v1",
"BASEHEROES": "Baseheroes",
"BASEPROTOCOL": "Base Protocol",
"BASESWAPX": "BaseX",
@ -1637,6 +1647,7 @@
"BASISSHAREV2": "Basis Share",
"BASK": "BasketDAO",
"BAST": "Bast",
"BASTEROID": "BABY ASTEROID",
"BASTET": "Bastet Goddess",
"BAT": "Basic Attention Token",
"BATCH": "BATCH Token",
@ -2584,7 +2595,7 @@
"BOZO": "BOZO",
"BOZOH": "bozo Hybrid",
"BOZY": "Book of Crazy",
"BP": "BunnyPark",
"BP": "Backpack",
"BPAD": "BlokPad",
"BPADA": "Binance-Peg Cardano (Binance Bridge)",
"BPAVAX": "Binance-Peg Avalanche (Binance Bridge)",
@ -2650,6 +2661,7 @@
"BREAD": "Breadchain Cooperative",
"BREE": "CBDAO",
"BREED": "BreederDAO",
"BRENT": "Brent Crude",
"BREPE": "BREPE",
"BRETARDIO": "Bretardio",
"BRETT": "Brett Base",
@ -2965,6 +2977,7 @@
"BULLA": "BULLA",
"BULLBEAR": "BullBear AI",
"BULLC": "BuySell",
"BULLDOG": "BullDog Coin",
"BULLF": "BULL FINANCE",
"BULLGOD": "Bull God",
"BULLI": "Bullish On Ethereum",
@ -2997,6 +3010,7 @@
"BUNNY": "Pancake Bunny",
"BUNNYINU": "Bunny Inu",
"BUNNYM": "BUNNY MEV BOT",
"BUNNYP": "BunnyPark",
"BUNNYROCKET": "BunnyRocket",
"BURG": "Burger",
"BURGER": "Burger Swap",
@ -3207,7 +3221,8 @@
"CARTIER": "Cartier",
"CARV": "CARV",
"CAS": "Cashaa",
"CASH": "CashCoin",
"CASH": "CASH",
"CASHCOIN": "CashCoin",
"CASHIO": "Cashio Dollar",
"CASHLY": "Cashly",
"CASHT": "Cash Tech",
@ -3232,7 +3247,7 @@
"CATCEO": "CATCEO",
"CATCH": "SpaceCatch",
"CATCO": "CatCoin",
"CATCOIN": "CatCoin",
"CATCOINCASH": "CatCoin",
"CATCOINETH": "Catcoin",
"CATCOINIO": "Catcoin",
"CATCOINOFSOL": "Cat Coin",
@ -3488,7 +3503,7 @@
"CHARTIQ": "ChartIQ",
"CHAS": "Chasm",
"CHASH": "CleverHash",
"CHAT": "Solchat",
"CHAT": "OpenChat",
"CHATAI": "ChatAI Token",
"CHATGPT": "AI Dragon",
"CHATOSHI": "chAtoshI",
@ -3826,7 +3841,8 @@
"COFIX": "CoFIX",
"COFOUNDIT": "Cofound.it",
"COG": "Cognitio",
"COGE": "Cogecoin",
"COGE": "Copper Doge",
"COGECOIN": "Cogecoin",
"COGEN": "Cogenero",
"COGI": "COGI",
"COGS": "Cogmento",
@ -4350,6 +4366,7 @@
"CWR": "Cowrium",
"CWS": "Crowns",
"CWT": "CrossWallet",
"CWU": "Commonwealth",
"CWV": "CryptoWave",
"CWX": "Crypto-X",
"CWXT": "CryptoWorldXToken",
@ -4673,6 +4690,7 @@
"DEFIK": "DeFi Kingdoms JADE",
"DEFIL": "DeFIL",
"DEFILAB": "Defi",
"DEFINITIVE": "Edge",
"DEFISCALE": "DeFiScale",
"DEFISSI": "DEFI.ssi",
"DEFIT": "Digital Fitness",
@ -5343,7 +5361,8 @@
"DTV": "DraperTV",
"DTX": "DataBroker DAO",
"DUA": "Brillion",
"DUAL": "Dual Finance",
"DUAL": "DUAL",
"DUALDAOTOKEN": "Dual Finance",
"DUB": "DubCoin",
"DUBAICAT": "Dubai Cat",
"DUBBZ": "Dubbz",
@ -5487,6 +5506,7 @@
"EARTH": "Earth Token",
"EARTHCOIN": "EarthCoin",
"EARTHM": "Earthmeta",
"EARTHY": "Little Earth Buddy",
"EASY": "EASY",
"EASYF": "EasyFeedback",
"EASYMINE": "EasyMine",
@ -5566,7 +5586,7 @@
"EDEXA": "edeXa Security Token",
"EDFI": "EdFi",
"EDG": "Edgeless",
"EDGE": "Definitive",
"EDGE": "edgeX",
"EDGEACTIVITY": "EDGE Activity Token",
"EDGEAI": "EdgeAI",
"EDGEN": "LayerEdge",
@ -5650,6 +5670,7 @@
"EIGENP": "Eigenpie",
"EIM": "Expert Infra",
"EIQT": "IQ Prediction",
"EITHER": "Eitherway",
"EJAC": "EJA Coin",
"EJS": "Enjinstarter",
"EKG": "Ekon Gold",
@ -5765,6 +5786,7 @@
"EML": "EML Protocol",
"EMMM": "emmm",
"EMN.CUR": "Eastman Chemical",
"EMOGINETWORK": "EMOGI Network",
"EMOJI": "MOMOJI",
"EMON": "Ethermon",
"EMONEYEUR": "e-Money EUR",
@ -6063,10 +6085,11 @@
"EUSX": "eUSX",
"EUT": "EarnUp Token",
"EUTBL": "Spiko EU T-Bills Money Market Fund",
"EV": "EVAI",
"EV": "Everything",
"EVA": "Evadore",
"EVAA": "EVAA Protocol",
"EVAI": "EVA Intelligence",
"EVAIIO": "EVAI",
"EVAL": "Chromia's EVAL by Virtuals",
"EVAN": "Evanesco Network",
"EVAULT": "EthereumVault",
@ -7101,6 +7124,7 @@
"GENIESWAP": "GenieSwap",
"GENIESWAPV1": "GenieSwap v1",
"GENIFYART": "Genify ART",
"GENIUS": "Genius",
"GENIX": "Genix",
"GENO": "GenomeFi",
"GENOME": "GenomesDao",
@ -7740,6 +7764,7 @@
"HACHIK": "Hachiko",
"HACHIKO": "Hachiko Inu Token",
"HACHIKOINU": "Hachiko Inu",
"HACHIKOTOKEN": "Hachiko",
"HACHIONB": "Hachi On Base",
"HACHITOKEN": "Hachi",
"HACK": "HACK",
@ -7747,6 +7772,7 @@
"HAEDAL": "Haedal Protocol",
"HAGGIS": "New Born Haggis Pygmy Hippo",
"HAHA": "Hasaki",
"HAHAYESRIZO": "Haha Yes Hedgehog",
"HAI": "Hacken Token",
"HAIO": "HAiO",
"HAIR": " HairDAO",
@ -7776,6 +7802,7 @@
"HANACOIN": "Hanacoin",
"HANAETH": "Hana",
"HANAETHCTO": "HANA",
"HANC": "OddHanc",
"HAND": "ShowHand",
"HANDY": "Handy",
"HANK": "Hank",
@ -7806,6 +7833,7 @@
"HASBIK": "Hasbulla",
"HASH": "Provenance Blockchain",
"HASHAI": "HashAI",
"HASHCOIN": "HASH Coin",
"HASHNET": "HashNet BitEco",
"HASHT": "HASH Token",
"HASUI": "Haedal",
@ -8411,6 +8439,7 @@
"IG": "IG Token ",
"IGCH": "IG-Crypto Holding",
"IGG": "IG Gold",
"IGGT": "The Invincible Game Token",
"IGI": "Igi",
"IGNIS": "Ignis",
"IGT": "Infinitar",
@ -8526,7 +8555,8 @@
"INNBC": "Innovative Bioresearch Coin",
"INNOU": "Innou",
"INNOVAMINEX": "InnovaMinex",
"INO": "Ino Coin",
"INO": "InoAi",
"INOCOIN": "Ino Coin",
"INOVAI": "INOVAI",
"INP": "Ionic Pocket Token",
"INRT": "INRToken",
@ -8709,6 +8739,7 @@
"IVY": "IvyKoin",
"IVZ": "InvisibleCoin",
"IW": "iWallet",
"IWC": "IWC",
"IWFT": "İstanbul Wild Cats",
"IWMON": "iShares Russell 2000 ETF (Ondo Tokenized)",
"IWT": "IwToken",
@ -9382,6 +9413,7 @@
"KRD": "Krypton DAO",
"KREDS": "KREDS",
"KREST": "krest Network",
"KRGN": "Kerrigan Network",
"KRIDA": "KridaFans",
"KRIPTO": "Kripto",
"KRL": "Kryll",
@ -9897,7 +9929,7 @@
"LOKA": "League of Kingdoms",
"LOKR": "Polkalokr",
"LOKY": "Loky by Virtuals",
"LOL": "EMOGI Network",
"LOL": "LOL",
"LOLA": "Lola",
"LOLATHECAT": "Lola",
"LOLC": "LOL Coin",
@ -9907,9 +9939,11 @@
"LOLO": "Lolo",
"LOLONBSC": "LOL",
"LON": "Tokenlon",
"LONG": "Longdrink Finance",
"LONG": "LONG",
"LONGDRINK": "Longdrink Finance",
"LONGEVITY": "longevity",
"LONGFU": "LONGFU",
"LONGFUN": "Long",
"LONGM": "Long Mao",
"LONGSHINE": "LongShine",
"LOOBY": "Looby by Stephen Bliss",
@ -10360,6 +10394,7 @@
"MAXL": "Maxi protocol",
"MAXR": "Max Revive",
"MAXX": "MAXX Finance",
"MAXXING": "Maxxing",
"MAY": "Mayflower",
"MAYA": "Maya",
"MAYACOIN": "MayaCoin",
@ -10667,6 +10702,8 @@
"MEXC": "MEXC Token",
"MEXP": "MOJI Experience Points",
"MEY": "Mey Network",
"MEZO": "MEZO",
"MEZOUSD": "Mezo USD",
"MEZZ": "MEZZ Token",
"MF": "Moonwalk Fitness",
"MF1": "Meta Finance",
@ -10713,7 +10750,8 @@
"MHT": "Mouse Haunt",
"MHUNT": "MetaShooter",
"MI": "XiaoMiCoin",
"MIA": "MiamiCoin",
"MIA": "MIA",
"MIAMICOIN": "MiamiCoin",
"MIAO": "MIAOCoin",
"MIB": "Mobile Integrated Blockchain",
"MIBO": "miBoodle",
@ -11034,7 +11072,7 @@
"MOLO": "MOLO CHAIN",
"MOLT": "Moltbook",
"MOLTID": "MoltID",
"MOM": "Mother of Memes",
"MOM": "MOM",
"MOMA": "Mochi Market",
"MOMIJI": "MAGA Momiji",
"MOMO": "Momo",
@ -11120,6 +11158,7 @@
"MOONEY": "Moon DAO",
"MOONI": "MOON INU",
"MOONION": "Moonions",
"MOONKIN": "MOONKIN",
"MOONKIZE": "MoonKize",
"MOONLIGHT": "Moonlight Token",
"MOONPIG": "Moonpig",
@ -11156,6 +11195,7 @@
"MOTG": "MetaOctagon",
"MOTH": "MOTH",
"MOTHER": "Mother Iggy",
"MOTHEROFMEMES": "Mother of Memes",
"MOTI": "Motion",
"MOTION": "motion",
"MOTIONCOIN": "Motion",
@ -12140,7 +12180,7 @@
"OEX": "OEX",
"OF": "OFCOIN",
"OFBC": "OneFinBank Coin",
"OFC": "$OFC Coin",
"OFC": "OneFootball Club",
"OFCR": "CryptoPolice",
"OFE": "Ofero",
"OFF": "BlastOff",
@ -12278,6 +12318,7 @@
"ONLINE": "Onlinebase",
"ONLY": "OnlyCam",
"ONLYCUMIES": "OnlyCumies",
"ONLYFANSCOINS": "$OFC Coin",
"ONNO": "Onno Vault",
"ONOMY": "Onomy Protocol",
"ONOT": "ONO",
@ -12506,6 +12547,7 @@
"OXY2": "Cryptoxygen",
"OXYC": "Oxycoin",
"OYS": "Oyster Platform",
"OYSTERPEARL": "Oyster Pearl",
"OZG": "Ozagold",
"OZK": "OrdiZK",
"OZMPC": "Ozempic",
@ -13021,7 +13063,6 @@
"PINMO": "Pinmo",
"PINO": "Pinocchu",
"PINS": "PINs Network Token",
"PINU": "Piccolo Inu",
"PINU100X": "Pi INU 100x",
"PIO": "Pioneershares",
"PIP": "Pip",
@ -13412,7 +13453,7 @@
"PRISMA": "Prisma Finance",
"PRIVIX": "Privix",
"PRIX": "Privatix",
"PRL": "Oyster Pearl",
"PRL": "Perle",
"PRM": "PrismChain",
"PRMX": "PREMA",
"PRNT": "Prime Numbers",
@ -13442,6 +13483,7 @@
"PROTEO": "Proteo DeFi",
"PROTO": "Protocon",
"PROTOCOLZ": "Protocol Zero",
"PROTOKEN": "Pro Token",
"PROTON": "Proton",
"PROUD": "PROUD Money",
"PROVE": "Succinct",
@ -13540,6 +13582,7 @@
"PUMPB": "Pump",
"PUMPBTC": "pumpBTC",
"PUMPBTCXYZ": "PumpBTC",
"PUMPCADE": "PUMPCADE",
"PUMPFUNBAN": "Pump Fun Ban",
"PUMPIT": "BOGDANOFF",
"PUMPTRUMP": "PUMP TRUMP",
@ -14058,6 +14101,7 @@
"RETSA": "Retsa Coin",
"REU": "REUCOIN",
"REUNI": "Reunit Wallet",
"REUR": "Royal Euro",
"REUSDC": "Relend USDC",
"REV": "Revain",
"REV3L": "REV3AL",
@ -14159,6 +14203,7 @@
"RIPTO": "RiptoBuX",
"RIS": "Riser",
"RISE": "EverRise",
"RISECOIN": "Rise coin",
"RISEP": "Rise Protocol",
"RISEVISION": "Rise",
"RISITA": "Risitas",
@ -14166,6 +14211,7 @@
"RITE": "ritestream",
"RITO": "Ritocoin",
"RITZ": "Ritz.Game",
"RIV": "RIV Coin",
"RIVER": "River",
"RIVERPTS": "River Point Reward Token",
"RIVUS": "RivusDAO",
@ -14602,7 +14648,7 @@
"SBCH": "Smart Bitcoin Cash",
"SBE": "Sombe",
"SBEFE": "BEFE",
"SBET": "SBET",
"SBET": "Sports Bet",
"SBF": "SBF In Jail",
"SBGO": "Bingo Share",
"SBIO": "Vector Space Biosciences, Inc.",
@ -15410,6 +15456,7 @@
"SOLCAT": "CatSolHat",
"SOLCATMEME": "SOLCAT",
"SOLCEX": "SolCex",
"SOLCHAT": "Solchat",
"SOLCHICKSSHARDS": "SolChicks Shards",
"SOLE": "SoleCoin",
"SOLER": "Solerium",
@ -15420,6 +15467,7 @@
"SOLFUN": "SolFun",
"SOLGOAT": "SOLGOAT",
"SOLGUN": "Solgun",
"SOLIB": "Solitaire Blossom",
"SOLIC": "Solice",
"SOLID": "Solidified",
"SOLIDSEX": "SOLIDsex: Tokenized veSOLID",
@ -15583,7 +15631,11 @@
"SPIDER": "Spider Man",
"SPIDERMAN": "SPIDERMAN BITCOIN",
"SPIDEY": "Spidey",
"SPIK": "Spike",
"SPIKE": "Spiking",
"SPIKE1984": "Spike 1984",
"SPIKECOIN": "SPIKE",
"SPIKEFURIE": "SPIKE",
"SPILLWAYS": "SpillWays",
"SPIN": "SPIN Protocol",
"SPINT": "Spintria",
@ -15591,6 +15643,7 @@
"SPITT": "Hawk Ttuuaahh",
"SPIZ": "SPACE-iZ",
"SPK": "Spark",
"SPKI": "SPIKE INU",
"SPKL": "SpokLottery",
"SPKTR": "Ghost Coin",
"SPKY": "GhostyCash",
@ -15612,6 +15665,7 @@
"SPOOL": "Spool DAO Token",
"SPORE": "Spore",
"SPORT": "SportsCoin",
"SPORTBET": "SBET",
"SPORTFUN": "Sport.fun",
"SPORTS": "ZenSports",
"SPORTSFIX": "SportsFix",
@ -16571,6 +16625,7 @@
"TKX": "Tokenize Xchange",
"TKY": "THEKEY Token",
"TLC": "Trillioner",
"TLF": "Tradeleaf",
"TLM": "Alien Worlds",
"TLN": "Trustlines Network",
"TLOS": "Telos",
@ -17075,6 +17130,7 @@
"UBQ": "Ubiq",
"UBT": "UniBright",
"UBTC": "UnitedBitcoin",
"UBU": "UBU",
"UBX": "UBIX Network",
"UBXN": "UpBots Token",
"UBXS": "UBXS",
@ -17169,6 +17225,7 @@
"UNBNK": "Unbanked",
"UNBREAKABLE": "UnbreakableCoin",
"UNC": "UnCoin",
"UNCEROID": "unc asteroid",
"UNCL": "UNCL",
"UNCN": "Unseen",
"UNCOMMONGOODS": "UNCOMMON•GOODS",
@ -17241,6 +17298,7 @@
"UNRC": "UniversalRoyalCoin",
"UNS": "UNS TOKEN",
"UNSHETH": "unshETH Ether",
"UNT": "Uni Token",
"UNW": "UniWorld",
"UOP": "Utopia Genesis Foundation",
"UOS": "UOS",
@ -17296,7 +17354,7 @@
"USDAI": "USDai",
"USDAP": "Bond Appetite USD",
"USDAVALON": "USDa",
"USDB": "USD Bancor",
"USDB": "Blynex USD",
"USDBC": "Bridged USDC",
"USDBLAST": "USDB Blast",
"USDC": "USD Coin",
@ -17412,13 +17470,14 @@
"UTNP": "Universa",
"UTON": "uTON",
"UTOPIA": "Utopia",
"UTOPIAUSD": "Utopia USD",
"UTT": "uTrade",
"UTU": "UTU Protocol",
"UTX": "UTIX",
"UTYA": "Utya",
"UTYAB": "Utya Black",
"UUC": "USA Unity Coin",
"UUSD": "Utopia USD",
"UUSD": "Unity USD",
"UUU": "U Network",
"UVT": "UvToken",
"UW3S": "Utility Web3Shot",
@ -17621,7 +17680,8 @@
"VIKKY": "VikkyToken",
"VILADY": "Vitalik Milady",
"VIM": "VicMove",
"VIN": "VinChain",
"VIN": "VulgarTycoon",
"VINCHAIN": "VinChain",
"VINCI": "VINCI",
"VINE": "Vine Coin",
"VINU": "Vita Inu",
@ -17716,6 +17776,7 @@
"VOL": "Volume Network",
"VOLBOOST": "VolBoost",
"VOLLAR": "Vollar",
"VOLM": "VOLM",
"VOLR": "Volare Network",
"VOLT": "Volt Inu",
"VOLTA": "Volta Club",
@ -18488,6 +18549,7 @@
"XCG": "Xchange",
"XCH": "Chia",
"XCHAT": "XChat",
"XCHATSOL": "XChat",
"XCHF": "CryptoFranc",
"XCHNG": "Chainge Finance",
"XCI": "Cannabis Industry Coin",
@ -18543,6 +18605,7 @@
"XENOVERSE": "Xenoverse",
"XEP": "Electra Protocol",
"XERA": "XERA",
"XERO": "XERO",
"XERS": "X Project",
"XES": "Proxeus",
"XET": "Xfinite Entertainment Token",

7
apps/api/src/services/data-provider/data-provider.service.ts

@ -12,6 +12,7 @@ import {
PROPERTY_DATA_SOURCE_MAPPING
} from '@ghostfolio/common/config';
import { CreateOrderDto } from '@ghostfolio/common/dtos';
import { SubscriptionType } from '@ghostfolio/common/enums';
import {
DATE_FORMAT,
getAssetProfileIdentifier,
@ -227,7 +228,7 @@ export class DataProviderService implements OnModuleInit {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
user.subscription.type === 'Basic'
user.subscription.type === SubscriptionType.Basic
) {
const dataProvider = this.getDataProvider(DataSource[dataSource]);
@ -591,7 +592,7 @@ export class DataProviderService implements OnModuleInit {
} else if (
dataProvider.getDataProviderInfo().isPremium &&
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
user?.subscription.type === 'Basic'
user?.subscription.type === SubscriptionType.Basic
) {
// Skip symbols of Premium data providers for users without subscription
return false;
@ -780,7 +781,7 @@ export class DataProviderService implements OnModuleInit {
})
.map((lookupItem) => {
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
if (user.subscription.type === 'Premium') {
if (user.subscription.type === SubscriptionType.Premium) {
lookupItem.dataProviderInfo.isPremium = false;
}

7
apps/client/src/app/components/admin-overview/admin-overview.component.ts

@ -8,7 +8,10 @@ import {
PROPERTY_SYSTEM_MESSAGE,
ghostfolioPrefix
} from '@ghostfolio/common/config';
import { ConfirmationDialogType } from '@ghostfolio/common/enums';
import {
ConfirmationDialogType,
SubscriptionType
} from '@ghostfolio/common/enums';
import { getDateFnsLocale } from '@ghostfolio/common/helper';
import {
Coupon,
@ -255,7 +258,7 @@ export class GfAdminOverviewComponent implements OnInit {
this.systemMessage ??
({
message: '⚒️ Scheduled maintenance in progress...',
targetGroups: ['Basic', 'Premium']
targetGroups: [SubscriptionType.Basic, SubscriptionType.Premium]
} as SystemMessage)
)
);

5
apps/client/src/app/pages/portfolio/fire/fire-page.component.ts

@ -1,5 +1,6 @@
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { SubscriptionType } from '@ghostfolio/common/enums';
import {
FireCalculationCompleteEvent,
FireWealth,
@ -80,7 +81,7 @@ export class GfFirePageComponent implements OnInit {
: 0
}
};
if (this.user.subscription?.type === 'Basic') {
if (this.user.subscription?.type === SubscriptionType.Basic) {
this.fireWealth = {
today: {
valueInBaseCurrency: 10000
@ -113,7 +114,7 @@ export class GfFirePageComponent implements OnInit {
this.user = state.user;
this.hasPermissionToUpdateUserSettings =
this.user.subscription?.type === 'Basic'
this.user.subscription?.type === SubscriptionType.Basic
? false
: hasPermission(
this.user.permissions,

3
apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts

@ -2,6 +2,7 @@ import { GfRulesComponent } from '@ghostfolio/client/components/rules/rules.comp
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { UpdateUserSettingDto } from '@ghostfolio/common/dtos';
import { SubscriptionType } from '@ghostfolio/common/enums';
import {
PortfolioReportResponse,
PortfolioReportRule
@ -73,7 +74,7 @@ export class GfXRayPageComponent {
this.user = state.user;
this.hasPermissionToUpdateUserSettings =
this.user.subscription?.type === 'Basic'
this.user.subscription?.type === SubscriptionType.Basic
? false
: hasPermission(
this.user.permissions,

7
apps/client/src/assets/oss-friends.json

@ -1,5 +1,5 @@
{
"createdAt": "2025-12-08T00:00:00.000Z",
"createdAt": "2026-04-21T00:00:00.000Z",
"data": [
{
"name": "Activepieces",
@ -21,11 +21,6 @@
"description": "Fastest LLM gateway with adaptive load balancer, cluster mode, guardrails, 1000+ models support & <100 µs overhead at 5k RPS.",
"href": "https://www.getmaxim.ai/bifrost"
},
{
"name": "Cal.com",
"description": "Cal.com is a scheduling tool that helps you schedule meetings without the back-and-forth emails.",
"href": "https://cal.com"
},
{
"name": "Cap",
"description": "Cap is the open source alternative to Loom. Lightweight, powerful, and cross-platform. Record and share securely in seconds.",

3707
package-lock.json

File diff suppressed because it is too large

42
package.json

@ -76,15 +76,15 @@
"@keyv/redis": "4.4.0",
"@nestjs/bull": "11.0.4",
"@nestjs/cache-manager": "3.1.0",
"@nestjs/common": "11.1.14",
"@nestjs/config": "4.0.3",
"@nestjs/core": "11.1.14",
"@nestjs/common": "11.1.19",
"@nestjs/config": "4.0.4",
"@nestjs/core": "11.1.19",
"@nestjs/event-emitter": "3.0.1",
"@nestjs/jwt": "11.0.2",
"@nestjs/passport": "11.0.5",
"@nestjs/platform-express": "11.1.14",
"@nestjs/schedule": "6.1.1",
"@nestjs/serve-static": "5.0.4",
"@nestjs/platform-express": "11.1.19",
"@nestjs/schedule": "6.1.3",
"@nestjs/serve-static": "5.0.5",
"@openrouter/ai-sdk-provider": "0.7.2",
"@prisma/adapter-pg": "7.7.0",
"@prisma/client": "7.7.0",
@ -107,7 +107,7 @@
"cookie-parser": "1.4.7",
"countries-and-timezones": "3.8.0",
"countries-list": "3.3.0",
"countup.js": "2.9.0",
"countup.js": "2.10.0",
"date-fns": "4.1.0",
"dotenv": "17.2.3",
"dotenv-expand": "12.0.3",
@ -118,7 +118,7 @@
"helmet": "7.0.0",
"http-status-codes": "2.3.0",
"ionicons": "8.0.13",
"jsonpath": "1.2.1",
"jsonpath": "1.3.0",
"lodash": "4.18.1",
"marked": "17.0.2",
"ms": "3.0.0-canary.1",
@ -156,18 +156,18 @@
"@angular/pwa": "21.2.6",
"@eslint/eslintrc": "3.3.1",
"@eslint/js": "9.35.0",
"@nestjs/schematics": "11.0.9",
"@nestjs/testing": "11.1.14",
"@nx/angular": "22.6.4",
"@nx/eslint-plugin": "22.6.4",
"@nx/jest": "22.6.4",
"@nx/js": "22.6.4",
"@nx/module-federation": "22.6.4",
"@nx/nest": "22.6.4",
"@nx/node": "22.6.4",
"@nx/storybook": "22.6.4",
"@nx/web": "22.6.4",
"@nx/workspace": "22.6.4",
"@nestjs/schematics": "11.1.0",
"@nestjs/testing": "11.1.19",
"@nx/angular": "22.6.5",
"@nx/eslint-plugin": "22.6.5",
"@nx/jest": "22.6.5",
"@nx/js": "22.6.5",
"@nx/module-federation": "22.6.5",
"@nx/nest": "22.6.5",
"@nx/node": "22.6.5",
"@nx/storybook": "22.6.5",
"@nx/web": "22.6.5",
"@nx/workspace": "22.6.5",
"@schematics/angular": "21.2.6",
"@storybook/addon-docs": "10.1.10",
"@storybook/angular": "10.1.10",
@ -193,7 +193,7 @@
"jest": "30.2.0",
"jest-environment-jsdom": "30.2.0",
"jest-preset-angular": "16.0.0",
"nx": "22.6.4",
"nx": "22.6.5",
"prettier": "3.8.2",
"prettier-plugin-organize-attributes": "1.0.0",
"prisma": "7.7.0",

Loading…
Cancel
Save