55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
import type { components } from "./generated/schema";
|
|
|
|
enum ApiErrorCode {
|
|
BankDependentRefunds = "BANK_DEPENDENT_REFUNDS",
|
|
BankIntentConflict = "BANK_INTENT_CONFLICT",
|
|
BankNotFound = "BANK_NOT_FOUND",
|
|
BankRefundLimit = "BANK_REFUND_LIMIT",
|
|
BankVersionConflict = "BANK_VERSION_CONFLICT",
|
|
BankWriteConflict = "BANK_WRITE_CONFLICT",
|
|
BondTickerAmbiguous = "BOND_TICKER_AMBIGUOUS",
|
|
InvalidOperationsCursor = "INVALID_OPERATIONS_CURSOR",
|
|
InvalidTbankToken = "INVALID_TBANK_TOKEN",
|
|
NotFound = "NOT_FOUND",
|
|
StockTickerAmbiguous = "STOCK_TICKER_AMBIGUOUS",
|
|
TbankNotConnected = "TBANK_NOT_CONNECTED",
|
|
TbankUnavailable = "TBANK_UNAVAILABLE",
|
|
Unauthorized = "UNAUTHORIZED",
|
|
}
|
|
|
|
/**
|
|
Compile-time drift guard: collapses to `never` when any enum member is absent
|
|
from the generated ProblemDetails contract, so every call site fails to build.
|
|
*/
|
|
type ContractApiErrorCode
|
|
= Exclude<
|
|
`${ApiErrorCode}`,
|
|
components["schemas"]["ProblemDetailsDto"]["code"]
|
|
> extends never ? ApiErrorCode : never;
|
|
|
|
function apiErrorCode(error: unknown): string | undefined {
|
|
return typeof error === "object" && error !== null && "code" in error
|
|
? String(error.code)
|
|
: undefined;
|
|
}
|
|
|
|
// Incoming codes are an open wire string; unknown values retain their fallback.
|
|
function isApiErrorCode(
|
|
value: unknown,
|
|
expected: ContractApiErrorCode,
|
|
): boolean {
|
|
return value === expected;
|
|
}
|
|
|
|
// Confirmed loss of access to the brokerage data. UNAUTHORIZED is a session
|
|
// failure with its own refresh/sign-out path, so it is deliberately excluded.
|
|
function isBrokerageAccessLoss(code?: string): boolean {
|
|
return [
|
|
ApiErrorCode.InvalidTbankToken,
|
|
ApiErrorCode.NotFound,
|
|
ApiErrorCode.TbankNotConnected,
|
|
].some(loss => isApiErrorCode(code, loss));
|
|
}
|
|
|
|
export { ApiErrorCode, apiErrorCode, isApiErrorCode, isBrokerageAccessLoss };
|