fix: translate permanent invalid-token errors on online entrypoints (WealthLedger/backend#59) (#110)
Backend verify / commits (push) Skipped
Backend verify / commits (pull_request) Failing after 33s
Backend verify / security (pull_request) Skipped
Backend verify / verify (pull_request) Skipped
Backend verify / security (push) Successful in 11s
Backend verify / verify (push) Failing after 6m40s
Backend verify / commits (push) Skipped
Backend verify / commits (pull_request) Failing after 33s
Backend verify / security (pull_request) Skipped
Backend verify / verify (pull_request) Skipped
Backend verify / security (push) Successful in 11s
Backend verify / verify (push) Failing after 6m40s
This commit was merged in pull request #110.
This commit is contained in:
@@ -122,11 +122,11 @@ export class CatalogDiscoveryService {
|
||||
observe = false,
|
||||
) {
|
||||
if (!observe) {
|
||||
const token = await this.access.onlineToken(userId);
|
||||
const instrument =
|
||||
const instrument = await this.access.online(userId, ({ token }) =>
|
||||
instrumentType === 'share'
|
||||
? await this.tbank.getShare(token, uid)
|
||||
: await this.tbank.getBond(token, uid);
|
||||
? this.tbank.getShare(token, uid)
|
||||
: this.tbank.getBond(token, uid),
|
||||
);
|
||||
if (!instrument) throw new NotFoundException();
|
||||
return {
|
||||
data: { ...publicInstrument({ ...instrument, uid }), uid, slug: instrument.ticker?.toUpperCase() ?? uid },
|
||||
@@ -201,11 +201,11 @@ export class CatalogDiscoveryService {
|
||||
) {
|
||||
if (!observe) {
|
||||
const query = ticker.trim().toUpperCase();
|
||||
const token = await this.access.onlineToken(userId);
|
||||
const found =
|
||||
const found = await this.access.online(userId, ({ token }) =>
|
||||
instrumentType === 'share'
|
||||
? await this.tbank.findShares(token, query)
|
||||
: await this.tbank.findBonds(token, query);
|
||||
? this.tbank.findShares(token, query)
|
||||
: this.tbank.findBonds(token, query),
|
||||
);
|
||||
const matches = selectCatalogInstruments(
|
||||
found.filter((item) => item.ticker?.trim().toUpperCase() === query),
|
||||
query,
|
||||
@@ -268,30 +268,32 @@ export class CatalogDiscoveryService {
|
||||
}
|
||||
|
||||
private async onlineSearch(userId: string, input: CatalogQuery) {
|
||||
const token = await this.access.onlineToken(userId);
|
||||
const found =
|
||||
input.instrumentType === 'share'
|
||||
? await this.tbank.findShares(token, input.query)
|
||||
: await this.tbank.findBonds(token, input.query);
|
||||
const instruments = selectCatalogInstruments(
|
||||
input.exactTicker
|
||||
? found.filter((item) => item.ticker?.trim().toUpperCase() === input.query)
|
||||
: found,
|
||||
input.query,
|
||||
input.instrumentType,
|
||||
).slice(FIRST_RESULT_OFFSET, input.exactTicker ? tickerAmbiguityLimit : catalogSearchLimit);
|
||||
const [details, prices] = await Promise.all([
|
||||
Promise.all(
|
||||
instruments.map((item) =>
|
||||
input.instrumentType === 'share'
|
||||
? this.tbank.getShare(token, item.uid)
|
||||
: this.tbank.getBond(token, item.uid),
|
||||
const { details, instruments, prices } = await this.access.online(userId, async ({ token }) => {
|
||||
const found =
|
||||
input.instrumentType === 'share'
|
||||
? await this.tbank.findShares(token, input.query)
|
||||
: await this.tbank.findBonds(token, input.query);
|
||||
const instruments = selectCatalogInstruments(
|
||||
input.exactTicker
|
||||
? found.filter((item) => item.ticker?.trim().toUpperCase() === input.query)
|
||||
: found,
|
||||
input.query,
|
||||
input.instrumentType,
|
||||
).slice(FIRST_RESULT_OFFSET, input.exactTicker ? tickerAmbiguityLimit : catalogSearchLimit);
|
||||
const [details, prices] = await Promise.all([
|
||||
Promise.all(
|
||||
instruments.map((item) =>
|
||||
input.instrumentType === 'share'
|
||||
? this.tbank.getShare(token, item.uid)
|
||||
: this.tbank.getBond(token, item.uid),
|
||||
),
|
||||
),
|
||||
),
|
||||
instruments.length
|
||||
? this.tbank.getLastPrices(token, instruments.map((item) => item.uid))
|
||||
: [],
|
||||
]);
|
||||
instruments.length
|
||||
? this.tbank.getLastPrices(token, instruments.map((item) => item.uid))
|
||||
: [],
|
||||
]);
|
||||
return { details, instruments, prices };
|
||||
});
|
||||
const fetchedAt = new Date();
|
||||
const data = instruments.flatMap((item, index) => {
|
||||
const detail = details.at(index);
|
||||
|
||||
@@ -231,7 +231,6 @@ export class CatalogEnrichmentService {
|
||||
return reservation;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity -- Section composition owns the source dependency policy.
|
||||
async section(
|
||||
userId: string,
|
||||
instrumentType: 'bond' | 'share',
|
||||
@@ -240,18 +239,20 @@ export class CatalogEnrichmentService {
|
||||
observe = false,
|
||||
) {
|
||||
if (section === 'company' && !observe) {
|
||||
const token = await this.access.onlineToken(userId);
|
||||
const instrument =
|
||||
instrumentType === 'share'
|
||||
? await this.tbank.getShare(token, uid)
|
||||
: await this.tbank.getBond(token, uid);
|
||||
if (!instrument) throw new NotFoundException();
|
||||
const [description, fundamentals] = instrument.assetUid
|
||||
? await Promise.all([
|
||||
this.tbank.getAssetDescription(token, instrument.assetUid),
|
||||
this.tbank.getFundamentals(token, instrument.assetUid),
|
||||
])
|
||||
: [null, null];
|
||||
const { description, fundamentals, instrument } = await this.access.online(userId, async ({ token }) => {
|
||||
const instrument =
|
||||
instrumentType === 'share'
|
||||
? await this.tbank.getShare(token, uid)
|
||||
: await this.tbank.getBond(token, uid);
|
||||
if (!instrument) throw new NotFoundException();
|
||||
const [description, fundamentals] = instrument.assetUid
|
||||
? await Promise.all([
|
||||
this.tbank.getAssetDescription(token, instrument.assetUid),
|
||||
this.tbank.getFundamentals(token, instrument.assetUid),
|
||||
])
|
||||
: [null, null];
|
||||
return { description, fundamentals, instrument };
|
||||
});
|
||||
const meta = investmentResourceMeta({
|
||||
resourceKey: `${instrumentType}/company/${uid}`,
|
||||
dataRevision: `online:${Date.now()}`,
|
||||
|
||||
+4
-2
@@ -22,14 +22,16 @@ function share(index: number, overrides: Partial<TbankShare> = {}): TbankShare {
|
||||
}
|
||||
|
||||
describe('StockScreenerService', () => {
|
||||
const access = { current: jest.fn(), local: jest.fn() };
|
||||
const access = { online: jest.fn(), local: jest.fn() };
|
||||
const client = { getAllShares: jest.fn() };
|
||||
const logger = { event: jest.fn() };
|
||||
let service: StockScreenerService;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
access.current.mockResolvedValue({ revision, token });
|
||||
access.online.mockImplementation((_userId: string, run: (connection: { revision: string; token: string }) => Promise<unknown>) =>
|
||||
run({ revision, token }),
|
||||
);
|
||||
access.local.mockResolvedValue({ revision });
|
||||
client.getAllShares.mockResolvedValue(
|
||||
Array.from({ length: pageSize + 1 }, (_, index) => share(index)),
|
||||
|
||||
@@ -48,8 +48,8 @@ type StockScreenerPage = {
|
||||
};
|
||||
type Snapshot = { asOf: string; expiresAt: number; items: StockScreenerItem[]; revision: string; userId: string };
|
||||
type TbankAccess = {
|
||||
current(userId: string): Promise<{ revision: string; token: string }>;
|
||||
local(userId: string): Promise<{ revision: string }>;
|
||||
online<T>(userId: string, run: (connection: { revision: string; token: string }) => Promise<T>): Promise<T>;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
@@ -63,8 +63,10 @@ export class StockScreenerService {
|
||||
) {}
|
||||
|
||||
async search(userId: string, conditions: StockScreenerConditions): Promise<StockScreenerPage> {
|
||||
const connection = await this.access.current(userId);
|
||||
const instruments = await this.client.getAllShares(connection.token);
|
||||
const { instruments, revision } = await this.access.online(userId, async (connection) => ({
|
||||
instruments: await this.client.getAllShares(connection.token),
|
||||
revision: connection.revision,
|
||||
}));
|
||||
const asOf = new Date().toISOString();
|
||||
const selected = selectStockScreenerInstruments({ asOf: new Date(asOf), instruments }, conditions)
|
||||
.instruments.map((instrument) => this.item(instrument));
|
||||
@@ -74,7 +76,7 @@ export class StockScreenerService {
|
||||
asOf,
|
||||
expiresAt: Date.now() + SNAPSHOT_TTL_MS,
|
||||
items: selected,
|
||||
revision: connection.revision,
|
||||
revision,
|
||||
userId,
|
||||
});
|
||||
this.logger.event('info', 'stock.screener.search.completed', { asOf, count: selected.length, operation: 'stock-screener-search' });
|
||||
|
||||
Reference in New Issue
Block a user