chore: strengthen backend eslint profile

This commit is contained in:
2026-09-28 16:37:01 +03:00
committed by ksv741
parent 53b2794963
commit a970eaaf7a
179 changed files with 4485 additions and 2716 deletions
@@ -1,43 +1,45 @@
import {
Injectable,
ConflictException,
Injectable,
NotFoundException,
ServiceUnavailableException,
} from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import type { InvestmentResourceMetaDto } from '../investment-resource.dto';
import {
InstrumentMetadataService,
TbankAccessService,
TbankMembershipService,
InstrumentMetadataService,
type TbankSyncAttempt,
} from '../../../integrations/tbank/tbank.api';
import { PortfolioService } from '../portfolio/portfolio.api';
import { BrokerageAccountsService } from '../brokerage-accounts/brokerage-accounts-read.api';
import { IncomeAnalyticsService } from '../income/income-read.api';
import {
BrokerageOperationsService,
BrokerageOperationsSyncService,
type OperationInterval,
} from '../operations/operations.api';
BondIncomeService,
StockIncomeService,
} from '../instruments/instrument-income.api';
import {
CandleService,
CatalogDiscoveryService,
CatalogEnrichmentService,
} from '../instruments/instruments.api';
import {
StockIncomeService,
BondIncomeService,
} from '../instruments/instrument-income.api';
import { BrokerageAccountsService } from '../brokerage-accounts/brokerage-accounts-read.api';
import { IncomeAnalyticsService } from '../income/income-read.api';
import { UpcomingEventsService } from '../upcoming-events/upcoming-events-read.api';
import { planInvestmentScreen } from '../investment-sync-plan';
import type { InvestmentResourceMetaDto } from '../investment-resource.dto';
import {
TbankSyncRepository,
type ScreenIntent,
} from './tbank-sync.repository';
import { InvestmentScreenDto, TbankSyncStatusDto } from './tbank-sync.dto';
import { normalizeScreen } from './tbank-screen';
import { investmentResourceMeta } from '../investment-resource.mapper';
import { planInvestmentScreen } from '../investment-sync-plan';
import {
BrokerageOperationsService,
BrokerageOperationsSyncService,
type OperationInterval,
} from '../operations/operations.api';
import { PortfolioService } from '../portfolio/portfolio.api';
import { UpcomingEventsService } from '../upcoming-events/upcoming-events-read.api';
import { normalizeScreen } from './tbank-screen';
import { InvestmentScreenDto, TbankSyncStatusDto } from './tbank-sync.dto';
import {
type ScreenIntent,
TbankSyncRepository,
} from './tbank-sync.repository';
@Injectable()
export class TbankSyncService {
@@ -88,7 +90,7 @@ export class TbankSyncService {
private async dispatch(attempt: TbankSyncAttempt, intent: ScreenIntent) {
const children: string[] = [];
const add = async (ids: (string | null | undefined)[]) => {
const add = async (ids: (null | string | undefined)[]) => {
children.push(...ids.filter((id): id is string => Boolean(id)));
await this.repository.progress(attempt, children, false);
};
@@ -107,14 +109,14 @@ export class TbankSyncService {
accountScope === 'all' || account.accountId === accountScope,
);
if (
['accounts', 'account', 'events', 'stock', 'bond'].includes(
['account', 'accounts', 'bond', 'events', 'stock'].includes(
scope.screen,
)
) {
for (const account of scope.screen === 'stock' ||
scope.screen === 'bond'
? current.accounts
: selectedAccounts) {
scope.screen === 'bond' ?
current.accounts :
selectedAccounts) {
const work = await this.portfolio.request(
userId,
revision,
@@ -127,9 +129,9 @@ export class TbankSyncService {
}
const saved = await this.portfolio.read(
userId,
scope.screen === 'stock' || scope.screen === 'bond'
? 'all'
: accountScope,
scope.screen === 'stock' || scope.screen === 'bond' ?
'all' :
accountScope,
true,
);
const positions = saved.data?.positions ?? [];
@@ -137,8 +139,8 @@ export class TbankSyncService {
...new Map(
positions.flatMap((position) =>
position.instrumentUid &&
(position.type === 'STOCK' || position.type === 'BOND')
? [
(position.type === 'STOCK' || position.type === 'BOND') ?
[
[
position.instrumentUid,
{
@@ -147,27 +149,27 @@ export class TbankSyncService {
historyFrom: null,
},
] as const,
]
: [],
] :
[],
),
).values(),
];
const plan = planInvestmentScreen(
{
...scope,
candleRange: scope.candleRange
? {
candleRange: scope.candleRange ?
{
from: new Date(scope.candleRange.from),
to: new Date(scope.candleRange.to),
}
: undefined,
} :
undefined,
},
{
accounts: selectedAccounts,
instruments:
scope.screen === 'stocks' || scope.screen === 'bonds'
? []
: instruments,
scope.screen === 'stocks' || scope.screen === 'bonds' ?
[] :
instruments,
membershipKnown: Boolean(current.membershipAt),
},
now,
@@ -177,20 +179,20 @@ export class TbankSyncService {
source.kind === 'operations' &&
source.accountId &&
source.from &&
source.to
? [
source.to ?
[
{
accountId: source.accountId,
from: source.from,
to: source.to,
...(source.instrumentUid
? { instrumentUid: source.instrumentUid }
: {}),
...(source.instrumentUid ?
{ instrumentUid: source.instrumentUid } :
{}),
},
]
: [],
] :
[],
);
if (intervals.length)
if (intervals.length) {
await add([
await this.operations.request(
userId,
@@ -200,24 +202,27 @@ export class TbankSyncService {
revision,
),
]);
}
for (const source of plan.sources) {
const uid = source.instrumentUid;
const type = source.instrumentType === 'BOND' ? 'bond' : 'share';
if (source.kind === 'catalog')
if (source.kind === 'catalog') {
await add(
await this.discovery.refresh(userId, revision, {
instrumentType: type,
query: source.query ?? '',
}),
);
}
if (!uid) continue;
if (source.kind === 'metadata')
if (source.kind === 'metadata') {
await add([
await this.metadata.request(userId, revision, {
instrumentUid: uid,
}),
]);
if (source.kind === 'quote')
}
if (source.kind === 'quote') {
await add(
await this.sources.requestMany(
userId,
@@ -233,7 +238,8 @@ export class TbankSyncService {
],
),
);
if (source.kind === 'company')
}
if (source.kind === 'company') {
await add(
await this.sources.requestMany(
userId,
@@ -244,7 +250,8 @@ export class TbankSyncService {
['description', 'fundamentals'],
),
);
if (source.kind === 'metrics')
}
if (source.kind === 'metrics') {
await add(
await this.sources.requestMany(
userId,
@@ -255,7 +262,8 @@ export class TbankSyncService {
['coupons', 'yield', 'rating'],
),
);
if (source.kind === 'calendar' && source.from && source.to)
}
if (source.kind === 'calendar' && source.from && source.to) {
await add(
await this.sources.requestMany(
userId,
@@ -264,11 +272,11 @@ export class TbankSyncService {
[uid],
true,
[
type === 'share'
? 'dividends'
: scope.screen === 'bond'
? 'coupons'
: 'bond-events',
type === 'share' ?
'dividends' :
scope.screen === 'bond' ?
'coupons' :
'bond-events',
],
{
from: source.from.toISOString().slice(0, 10),
@@ -279,6 +287,7 @@ export class TbankSyncService {
},
),
);
}
}
if (
(scope.screen === 'stock' || scope.screen === 'bond') &&
@@ -292,14 +301,14 @@ export class TbankSyncService {
uid: scope.instrumentUid,
instrumentType: scope.screen === 'bond' ? 'bond' : 'share',
period: scope.candlePeriod ?? 'month',
...(scope.candleRange
? {
...(scope.candleRange ?
{
range: {
from: new Date(scope.candleRange.from),
to: new Date(scope.candleRange.to),
},
}
: {}),
} :
{}),
},
now,
true,
@@ -324,15 +333,16 @@ export class TbankSyncService {
});
const saved = await this.repository.read(userId, connection.revision, id);
if (!saved) throw new NotFoundException();
if (!saved.work.scopeKey.startsWith('screen:'))
if (!saved.work.scopeKey.startsWith('screen:')) {
return this.sourceStatus(userId, saved.work);
}
const intent = saved.work.intent as unknown as ScreenIntent;
await this.access.local(userId, intent.scope.accountId);
const children = await Promise.all(
saved.children.map((child) =>
child.state === 'superseded'
? this.operations.observe(userId, child.id)
: Promise.resolve(child),
child.state === 'superseded' ?
this.operations.observe(userId, child.id) :
Promise.resolve(child),
),
);
const running = children.some((child) => child.state === 'running');
@@ -342,21 +352,22 @@ export class TbankSyncService {
null;
const state =
saved.work.processRunId !== this.runId &&
(!saved.progress.dispatched || running)
? 'cancelled'
: !saved.progress.dispatched || running
? 'running'
: failed
? 'failed'
: children.some((child) => child.state === 'cancelled')
? 'cancelled'
: 'succeeded';
(!saved.progress.dispatched || running) ?
'cancelled' :
!saved.progress.dispatched || running ?
'running' :
failed ?
'failed' :
children.some((child) => child.state === 'cancelled') ?
'cancelled' :
'succeeded';
const resources = await this.observe(userId, intent.scope);
if (
(await this.access.local(userId, intent.scope.accountId)).revision !==
connection.revision
)
) {
throw new NotFoundException();
}
return {
id,
...intent,
@@ -380,16 +391,16 @@ export class TbankSyncService {
const add = async (read: Promise<{ meta: InvestmentResourceMetaDto }>) => {
resources.push((await read).meta);
};
if (work.scopeKey === 'membership')
if (work.scopeKey === 'membership') {
await add(this.accounts.list(userId, true));
else if (
} else if (
input.source === 'portfolio' &&
typeof input.accountId === 'string'
)
) {
await add(this.portfolio.read(userId, input.accountId, true));
else if (input.source === 'catalog') {
} else if (input.source === 'catalog') {
const type = input.instrumentType === 'bond' ? 'bond' : 'share';
if (typeof input.query === 'string')
if (typeof input.query === 'string') {
await add(
this.discovery.search(
userId,
@@ -401,14 +412,14 @@ export class TbankSyncService {
true,
),
);
else if (
} else if (
typeof input.uid === 'string' &&
typeof input.kind === 'string'
) {
const range =
typeof input.rangeKey === 'string' && input.rangeKey.startsWith('[')
? (JSON.parse(input.rangeKey) as string[])
: null;
typeof input.rangeKey === 'string' && input.rangeKey.startsWith('[') ?
(JSON.parse(input.rangeKey) as string[]) :
null;
const sources = await this.sources.readMany(
userId,
type,
@@ -417,9 +428,9 @@ export class TbankSyncService {
[
input.kind as Parameters<
CatalogEnrichmentService['readMany']
>[4] extends (infer K)[] | undefined
? K
: never,
>[4] extends (infer K)[] | undefined ?
K :
never,
],
range ? { from: range[0], to: range[1] } : undefined,
);
@@ -452,7 +463,7 @@ export class TbankSyncService {
{
uid: input.uid,
instrumentType: input.instrumentType === 'bond' ? 'bond' : 'share',
period: input.period as 'month' | 'halfYear' | 'year' | 'all',
period: input.period as 'all' | 'halfYear' | 'month' | 'year',
},
true,
),
@@ -475,21 +486,22 @@ export class TbankSyncService {
);
}
}
const observed = work.scopeKey.startsWith('operations:')
? await this.operations.observe(userId, work.id)
: work;
const observed = work.scopeKey.startsWith('operations:') ?
await this.operations.observe(userId, work.id) :
work;
const state =
observed.state === 'running'
? observed.updatedAt < this.startedAt
? 'cancelled'
: 'running'
: observed.state === 'failed'
? 'failed'
: observed.state === 'cancelled'
? 'cancelled'
: 'succeeded';
if ((await this.access.local(userId)).revision !== work.revision)
observed.state === 'running' ?
observed.updatedAt < this.startedAt ?
'cancelled' :
'running' :
observed.state === 'failed' ?
'failed' :
observed.state === 'cancelled' ?
'cancelled' :
'succeeded';
if ((await this.access.local(userId)).revision !== work.revision) {
throw new NotFoundException();
}
return {
id: work.id,
scope: null,
@@ -511,14 +523,15 @@ export class TbankSyncService {
resources.push((await read).meta);
};
const account = scope.accountId ?? 'all';
if (scope.screen === 'accounts')
if (scope.screen === 'accounts') {
await add(this.accounts.list(userId, true));
}
if (scope.screen === 'account') {
await add(this.portfolio.read(userId, account, true));
await add(this.income.summary(userId, account, true));
await add(this.events.get(userId, account, { sync: 'observe' }));
}
if (['account', 'operations', 'stock', 'bond'].includes(scope.screen))
if (['account', 'bond', 'operations', 'stock'].includes(scope.screen)) {
await add(
this.ledger.read(userId, account, {
from: scope.from,
@@ -529,11 +542,13 @@ export class TbankSyncService {
sync: 'observe',
}),
);
if (scope.screen === 'income')
}
if (scope.screen === 'income') {
await add(
this.income.analytics(userId, account, scope.from, scope.to, true),
);
if (scope.screen === 'events')
}
if (scope.screen === 'events') {
await add(
this.events.get(userId, account, {
from: scope.from,
@@ -541,9 +556,10 @@ export class TbankSyncService {
sync: 'observe',
}),
);
}
const type =
scope.screen === 'bond' || scope.screen === 'bonds' ? 'bond' : 'share';
if (scope.screen === 'stocks' || scope.screen === 'bonds')
if (scope.screen === 'stocks' || scope.screen === 'bonds') {
await add(
this.discovery.search(
userId,
@@ -551,6 +567,7 @@ export class TbankSyncService {
true,
),
);
}
if (
(scope.screen === 'stock' || scope.screen === 'bond') &&
scope.instrumentUid
@@ -574,27 +591,27 @@ export class TbankSyncService {
uid,
instrumentType: type,
period: scope.candlePeriod ?? 'month',
...(scope.candleRange
? {
...(scope.candleRange ?
{
range: {
from: new Date(scope.candleRange.from),
to: new Date(scope.candleRange.to),
},
}
: {}),
} :
{}),
},
true,
),
);
await add(
type === 'share'
? this.stockIncome.readPosition(userId, uid, true)
: this.bondIncome.readPosition(userId, uid, true),
type === 'share' ?
this.stockIncome.readPosition(userId, uid, true) :
this.bondIncome.readPosition(userId, uid, true),
);
await add(
type === 'share'
? this.stockIncome.dividends(userId, uid, true)
: this.bondIncome.coupons(userId, uid, true),
type === 'share' ?
this.stockIncome.dividends(userId, uid, true) :
this.bondIncome.coupons(userId, uid, true),
);
}
return resources;