chore: strengthen backend eslint profile
This commit is contained in:
@@ -1,23 +1,24 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
import { StructuredLogger } from '../../common/logging/structured-logger.service';
|
||||
import {
|
||||
InstrumentMetadataRepository,
|
||||
type MetadataIdentity,
|
||||
metadataKey,
|
||||
type MetadataLookup,
|
||||
} from './instrument-metadata.repository';
|
||||
import {
|
||||
TbankAccessService,
|
||||
type TbankSyncAttempt,
|
||||
} from './tbank-access.service';
|
||||
import { TbankClient, type TbankInstrument } from './tbank.client';
|
||||
import {
|
||||
InstrumentMetadataRepository,
|
||||
metadataKey,
|
||||
type MetadataIdentity,
|
||||
type MetadataLookup,
|
||||
} from './instrument-metadata.repository';
|
||||
export { metadataKey } from './instrument-metadata.repository';
|
||||
export type { MetadataIdentity } from './instrument-metadata.repository';
|
||||
|
||||
type Producer = {
|
||||
identity: MetadataIdentity;
|
||||
attempt: TbankSyncAttempt;
|
||||
identity: MetadataIdentity;
|
||||
observers: TbankSyncAttempt[];
|
||||
};
|
||||
@Injectable()
|
||||
@@ -49,8 +50,9 @@ export class InstrumentMetadataService {
|
||||
const connection = await this.access.local(userId);
|
||||
if (revision && connection.revision !== revision) return null;
|
||||
const data = (await this.savedMany([identity])).get(metadataKey(identity));
|
||||
if (!observe && !data?.fresh)
|
||||
if (!observe && !data?.fresh) {
|
||||
await this.request(userId, connection.revision, identity);
|
||||
}
|
||||
return {
|
||||
...data,
|
||||
work: await this.repository.work(userId, connection.revision, identity),
|
||||
@@ -119,7 +121,7 @@ export class InstrumentMetadataService {
|
||||
let useful = false;
|
||||
let uidFailed = false;
|
||||
if (identity.instrumentUid) {
|
||||
let data: TbankInstrument | null | undefined;
|
||||
let data: null | TbankInstrument | undefined;
|
||||
try {
|
||||
data = await this.tbank.getInstrumentByUid(
|
||||
token,
|
||||
@@ -130,29 +132,37 @@ export class InstrumentMetadataService {
|
||||
!identity.figi ||
|
||||
(error instanceof Error &&
|
||||
error.message === 'INVALID_TBANK_TOKEN')
|
||||
)
|
||||
) {
|
||||
throw error;
|
||||
}
|
||||
uidFailed = true;
|
||||
}
|
||||
if (data?.uid && data.uid !== identity.instrumentUid)
|
||||
if (data?.uid && data.uid !== identity.instrumentUid) {
|
||||
throw new Error('Metadata UID mismatch');
|
||||
if (data !== undefined)
|
||||
}
|
||||
if (data !== undefined) {
|
||||
results.push({ type: 'uid', id: identity.instrumentUid, data });
|
||||
}
|
||||
useful = Boolean(data?.name?.trim() || data?.ticker?.trim());
|
||||
if (!useful && data && !identity.figi)
|
||||
if (!useful && data && !identity.figi) {
|
||||
throw new Error('Incomplete metadata');
|
||||
}
|
||||
}
|
||||
if (!useful && identity.figi) {
|
||||
const data = await this.tbank.getInstrumentByFigi(
|
||||
token,
|
||||
identity.figi,
|
||||
);
|
||||
if (data?.figi && data.figi !== identity.figi)
|
||||
if (data?.figi && data.figi !== identity.figi) {
|
||||
throw new Error('Metadata FIGI mismatch');
|
||||
if (data && !data.name?.trim() && !data.ticker?.trim())
|
||||
}
|
||||
if (data && !data.name?.trim() && !data.ticker?.trim()) {
|
||||
throw new Error('Incomplete metadata');
|
||||
if (data === undefined || (uidFailed && !data))
|
||||
}
|
||||
// eslint-disable-next-line sonarjs/different-types-comparison -- Defensive validation at an untrusted upstream boundary includes missing payloads.
|
||||
if (data === undefined || (uidFailed && !data)) {
|
||||
throw new Error('Metadata source unavailable');
|
||||
}
|
||||
results.push({ type: 'figi', id: identity.figi, data });
|
||||
// A successful FIGI response identifies its canonical UID too;
|
||||
// a failed UID RPC is never persisted as a negative lookup.
|
||||
@@ -160,8 +170,9 @@ export class InstrumentMetadataService {
|
||||
uidFailed &&
|
||||
data?.uid === identity.instrumentUid &&
|
||||
identity.instrumentUid
|
||||
)
|
||||
) {
|
||||
results.push({ type: 'uid', id: identity.instrumentUid, data });
|
||||
}
|
||||
}
|
||||
if (
|
||||
!results.length ||
|
||||
@@ -170,8 +181,9 @@ export class InstrumentMetadataService {
|
||||
(result) =>
|
||||
result.data?.name?.trim() || result.data?.ticker?.trim(),
|
||||
))
|
||||
)
|
||||
) {
|
||||
throw new Error('Incomplete metadata');
|
||||
}
|
||||
success = await this.repository.publish(
|
||||
attempt,
|
||||
results,
|
||||
@@ -179,12 +191,13 @@ export class InstrumentMetadataService {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message === 'INVALID_TBANK_TOKEN')
|
||||
if (error instanceof Error && error.message === 'INVALID_TBANK_TOKEN') {
|
||||
await this.access.rejectMembershipToken(attempt);
|
||||
else
|
||||
} else {
|
||||
this.logger.event('warn', 'instrument-metadata.failed', {
|
||||
code: 'TBANK_UNAVAILABLE',
|
||||
});
|
||||
}
|
||||
}
|
||||
// Remove the producer before awaiting finalization: a new request cannot
|
||||
// attach to a producer whose observer list has already been drained.
|
||||
|
||||
Reference in New Issue
Block a user