Перейти к содержимому
Справочник SDK

TypeScript SDK

Клиент, стрим, поиск терминала и ошибки пакета @spectre-trade/terminal.

Установка

npm install @spectre-trade/terminal

Terminal

Клиент одного запущенного терминала.

Создайте его с токеном или дайте Terminal.discover найти порт и токен и проверить версию API. Все методы async и бросают ApiError на ответ не 2xx и TerminalUnreachableError, когда ответа нет.

ПолеТипОписание
hoststring
portnumber
timeoutMsnumber
baseUrlstringhttp://127.0.0.1:48180/v1/ — токен в него не входит.

Terminal()

new Terminal(options: TerminalOptions)

discover()

static discover(options: DiscoverOptions = {}): Promise<Terminal>

Найти терминал и проверить его: токен из options.token или SPECTRE_LOCAL_API_TOKEN (иначе TokenMissingError), порт из options.port или instance.json (иначе 48180; LocalApiDisabledError, если файл говорит, что API выключен), затем один GET /v1/meta. api_version, отличный от "1", — это IncompatibleTerminalError; ответ unauthorized — это ApiError, чьё сообщение говорит, что токен мог устареть или API выключен.

ОпцииТипОписание
tokenнеобязательныйstringИмеет приоритет над SPECTRE_LOCAL_API_TOKEN.
portнеобязательныйnumberИмеет приоритет над instance.json.
hostнеобязательныйstring
timeoutMsнеобязательныйnumber
instancePathнеобязательныйstringЧитать этот файл вместо пути к instance.json, зависящего от ОС (для тестов).

meta()

meta(): Promise<Meta>

GET /v1/meta: версия API, сборка, права токена, лимиты, топики стрима.

Операция HTTP: GET /v1/meta

health()

health(): Promise<Health>

GET /v1/health.

Операция HTTP: GET /v1/health

connections()

connections(): Promise<List<Connection>>

GET /v1/connections (connections:read).

Операция HTTP: GET /v1/connections

connection()

connection(id: number): Promise<Connection>

GET /v1/connections/{id} (connections:read); not_found для неизвестного id.

Операция HTTP: GET /v1/connections/{id}

instruments()

instruments(options: InstrumentsOptions): Promise<InstrumentsPage>

GET /v1/instruments (market:read): одна страница справочника биржи и рынка, по connectionId или exchange + market. Листайте по next_cursor сами или используйте iterInstruments.

Операция HTTP: GET /v1/instruments

ОпцииТипОписание
connectionIdнеобязательныйnumber
exchangeнеобязательныйstring
marketнеобязательныйstring
qнеобязательныйstringПодстрока символа или базовой монеты, без учёта регистра.
limitнеобязательныйnumber1–2000, по умолчанию 500.
cursorнеобязательныйstringnext_cursor предыдущей страницы.

iterInstruments()

iterInstruments(options: InstrumentsOptions): AsyncGenerator<Instrument, void, undefined>

Все инструменты, подходящие под параметры, страница за страницей.

ОпцииТипОписание
connectionIdнеобязательныйnumber
exchangeнеобязательныйstring
marketнеобязательныйstring
qнеобязательныйstringПодстрока символа или базовой монеты, без учёта регистра.
limitнеобязательныйnumber1–2000, по умолчанию 500.
cursorнеобязательныйstringnext_cursor предыдущей страницы.

intervals()

intervals(): Promise<Intervals>

GET /v1/market/intervals (market:read): интервалы свечей и кластеров.

Операция HTTP: GET /v1/market/intervals

candles()

candles(instrument: InstrumentAddress, options: CandlesOptions): Promise<Candles>

GET /v1/market/candles (market:read): история свечей, от старых к новым.

Операция HTTP: GET /v1/market/candles

ОпцииТипОписание
intervalstringКод из /v1/market/intervals: 1m, 5m, …
limitнеобязательныйnumberДо 2000, по умолчанию 500.
endнеобязательныйnumberПравая граница, миллисекунды UTC; по умолчанию — сейчас.
connectionIdнеобязательныйnumber

trades()

trades(instrument: InstrumentAddress, options: TradesOptions = {}): Promise<Trades>

GET /v1/market/trades (market:read): последние сделки пары, от старых к новым. Пара без подписки открывается по запросу, и вызов может занять до 3 с.

Операция HTTP: GET /v1/market/trades

ОпцииТипОписание
limitнеобязательныйnumber1–1000 последних, по умолчанию 100.
sinceTsнеобязательныйnumberНе раньше этого времени получения, миллисекунды UTC.
connectionIdнеобязательныйnumber

snapshot()

snapshot(instrument: InstrumentAddress, options: ConnectionOptions = {}): Promise<Snapshot>

GET /v1/market/snapshot (market:read): лучшие bid/ask, последняя сделка, mark, тикер.

Операция HTTP: GET /v1/market/snapshot

ОпцииТипОписание
connectionIdнеобязательныйnumber

orderbook()

orderbook(instrument: InstrumentAddress, options: OrderbookOptions = {}): Promise<Orderbook>

GET /v1/market/orderbook (market:read); unavailable, если полный стакан не пришёл за 3 с.

Операция HTTP: GET /v1/market/orderbook

ОпцииТипОписание
depthнеобязательныйnumber1–200, по умолчанию 50.
connectionIdнеобязательныйnumber

clusters()

clusters(instrument: InstrumentAddress, options: ConnectionOptions = {}): Promise<Clusters>

GET /v1/market/clusters (market:read): до десяти бакетов с интервалом, выбранным в терминале. Первый вызов для инструмента, не открытого в окне, может ответить not_active (409); повтор через несколько секунд кластеры находит.

Операция HTTP: GET /v1/market/clusters

ОпцииТипОписание
connectionIdнеобязательныйnumber

accountOrders()

accountOrders(connectionId: number): Promise<AccountOrders>

GET /v1/account/orders (account:read): открытые заявки и триггерные заявки одного подключения, тот же срез, что видит окно терминала. not_found для неизвестного подключения.

Операция HTTP: GET /v1/account/orders

accountPositions()

accountPositions(connectionId: number): Promise<AccountPositions>

GET /v1/account/positions (account:read): открытые позиции одного подключения.

Операция HTTP: GET /v1/account/positions

accountBalances()

accountBalances(connectionId: number): Promise<AccountBalances>

GET /v1/account/balances (account:read): по каждой валюте последнее значение, которое биржа прислала с момента включения API. Валюты, с которой с тех пор ничего не происходило, в ответе нет.

Операция HTTP: GET /v1/account/balances

accountFills()

accountFills(connectionId: number, options: AccountFillsOptions = {}): Promise<AccountFills>

GET /v1/account/fills (account:read): исполнения подключения с момента включения API (последняя тысяча), от старых к новым.

Операция HTTP: GET /v1/account/fills

ОпцииТипОписание
limitнеобязательныйnumber1–1000 последних, по умолчанию 100.
sinceTsнеобязательныйnumberНе раньше этого времени биржи, миллисекунды UTC.

placeOrder()

placeOrder(options: PlaceOrderOptions): Promise<Accepted>

POST /v1/orders (trading:write): поставить лимитную или рыночную заявку той же командой, что использует окно. Ответ значит «принято терминалом», а не биржей: следите за account.orders в стриме или за accountOrders — заявка там под ключом key. not_tradable (409) для выключенного подключения, подключения только для чтения или без учётных данных, invalid_request (400) для чужого инструмента или отклонённых размера или цены, rate_limited (429) выше limits.commands_per_second.

Операция HTTP: POST /v1/orders

ОпцииТипОписание
connectionIdnumberТорговое подключение; умолчания нет.
instrumentInstrumentAddress
sideSide
typeOrderTypelimit требует price, market его не принимает.
priceнеобязательныйDecimal
sizeнеобязательныйDecimalКоличество в базовой монете; ровно одно из size и notional.
notionalнеобязательныйDecimalСумма в валюте котировки; ровно одно из size и notional.
reduceOnlyнеобязательныйbooleanПо умолчанию false.
postOnlyнеобязательныйbooleanПо умолчанию false.
timeInForceнеобязательныйTimeInForceОтсутствует — умолчание площадки.
clientKeyнеобязательныйstringКлюч идемпотентности: повтор с тем же ключом возвращает прежний ответ и не дублирует заявку (терминал помнит последнюю тысячу).

cancelOrder()

cancelOrder(options: CancelOrderOptions): Promise<Accepted>

DELETE /v1/orders/{id} (trading:write): снять одну заявку по ключу терминала (t-…) или биржевому id. Снятие уходит на биржу напрямую; подтверждение приходит через стрим.

Операция HTTP: DELETE /v1/orders/{id}

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress
orderIdstringКлюч терминала (t-…) или биржевой id заявки.

cancelAll()

cancelAll(options: InstrumentCommandOptions): Promise<Accepted>

POST /v1/orders/cancel-all (trading:write): снять все заявки инструмента, как это делает пробел.

Операция HTTP: POST /v1/orders/cancel-all

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress

closePosition()

closePosition(options: InstrumentCommandOptions): Promise<Accepted>

POST /v1/positions/close (trading:write): закрыть позицию по инструменту так, как это делает окно, — рыночной заявкой на размер позиции на фьючерсах, одной атомарной командой «снять всё и закрыть» на споте. invalid_request без открытой позиции.

Операция HTTP: POST /v1/positions/close

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress

placeTrigger()

placeTrigger(options: PlaceTriggerOptions): Promise<Accepted>

POST /v1/orders/trigger (trading:write): стоп-лосс, тейк-профит или стоп, поставленные теми же сервисами, что использует окно. stop_loss и take_profit ставятся на открытую позицию (сторона, размер и правило берутся из неё; invalid_request без позиции); для stop нужны side и notional. key в ответе — ключ триггера (sl_…, tp_…, stop_…), который виден как client_id триггера в accountOrders; снятие и правка используют числовой id оттуда. unsupported (501) на площадке без триггерных заявок в терминале.

Операция HTTP: POST /v1/orders/trigger

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress
kindTriggerTypestop_loss и take_profit ставятся на открытую позицию; stop — самостоятельная заявка.
triggerPriceDecimal
sideнеобязательныйSideТолько для stop.
notionalнеобязательныйDecimalТолько для stop: сумма в валюте котировки.
ruleнеобязательныйTriggerRuleТолько для stop; без него — выше рынка для покупки, ниже для продажи.
clientKeyнеобязательныйstringКлюч идемпотентности, как у Terminal.placeOrder.

cancelTrigger()

cancelTrigger(options: CancelTriggerOptions): Promise<Accepted>

DELETE /v1/orders/trigger/{id} (trading:write): снять один триггер по его числовому id.

Операция HTTP: DELETE /v1/orders/trigger/{id}

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress
triggerIdstring | numberЧисловой id триггера из accountOrders().triggers.

cancelAllTriggers()

cancelAllTriggers(options: InstrumentCommandOptions): Promise<Accepted>

POST /v1/orders/trigger/cancel-all (trading:write): снять все триггеры инструмента; обычные заявки остаются.

Операция HTTP: POST /v1/orders/trigger/cancel-all

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress

amendTrigger()

amendTrigger(options: AmendTriggerOptions): Promise<Accepted>

PATCH /v1/orders/trigger/{id} (trading:write): перенести триггер на новую цену — последовательная замена, как в окне: снять, затем поставить. kind обязателен; для stop нужен ещё и его side. key равен null.

Операция HTTP: PATCH /v1/orders/trigger/{id}

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress
triggerIdstring | numberЧисловой id триггера из accountOrders().triggers.
kindTriggerType
triggerPriceDecimal
sideнеобязательныйSideТолько для stop.
ruleнеобязательныйTriggerRuleТолько для stop.

leverage()

leverage(options: InstrumentCommandOptions): Promise<Leverage>

GET /v1/account/leverage (account:read): плечо и режим маржи фьючерсного инструмента из кэша терминала. Инструмент, которого терминал ещё не касался, — not_active (409): откройте его в окне или вызовите setLeverage — так он попадает в кэш.

Операция HTTP: GET /v1/account/leverage

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress

setLeverage()

setLeverage(options: SetLeverageOptions): Promise<Accepted>

POST /v1/account/leverage (trading:write): задать плечо так, как это делает окно, — ровно одно из leverage (целое ≥ 1) и mode (max, smart). Применённое значение видно в leverage после ответа биржи.

Операция HTTP: POST /v1/account/leverage

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress
leverageнеобязательныйnumberЦелое число не меньше 1.
modeнеобязательный"max" | "smart"

setMarginMode()

setMarginMode(options: SetMarginModeOptions): Promise<Accepted>

POST /v1/account/margin-mode (trading:write): cross или isolated. Смену при открытой позиции биржа отклоняет, как и в окне; ответ accepted этого ещё не знает.

Операция HTTP: POST /v1/account/margin-mode

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress
marginModeMarginMode

workspace()

workspace(): Promise<Workspace>

GET /v1/workspace (workspace:read): все окна с их вкладками, стеками и графиками из снимка, который окно публикует при каждом изменении структуры. Идентификаторы внутренние для этого запуска терминала.

Операция HTTP: GET /v1/workspace

workspaceWindow()

workspaceWindow(options: WindowOptions): Promise<WorkspaceWindow>

GET /v1/workspace/windows/{id} (workspace:read): одно окно; неизвестный id — not_found.

Операция HTTP: GET /v1/workspace/windows/{id}

ОпцииТипОписание
windowIdnumber

openStack()

openStack(options: OpenStackOptions): Promise<WorkspaceOutcome>

POST /v1/workspace/stacks (workspace:write): стек инструмента в новой вкладке или новом окне, с графиком над ним, если задан chart. Ответ называет окно, вкладку и новые виджеты. Инструмент, которого справочник терминала не знает, — invalid_request.

Операция HTTP: POST /v1/workspace/stacks

ОпцииТипОписание
instrumentInstrumentAddress
connectionIdнеобязательныйnumberБез него выбирается по общему правилу.
chartнеобязательныйbooleanГрафик того же инструмента над стеком.
targetнеобязательныйOpenTargetnew_tab (по умолчанию) или new_window.
windowIdнеобязательныйnumberОкно для новой вкладки; без него — окно в фокусе.
activateнеобязательныйbooleanfalse открывает вкладку в фоне; новое окно всегда получает фокус.

openTab()

openTab(options: OpenTabOptions): Promise<WorkspaceOutcome>

POST /v1/workspace/tabs (workspace:write): вкладка с колонкой на элемент — стек и, с chart, график над ним — в новой вкладке или новом окне. Без name имя — единственный инструмент или первый плюс число остальных. Отказ называет элемент (items[1]: …), и до окна не доходит ничего.

Операция HTTP: POST /v1/workspace/tabs

ОпцииТипОписание
itemsArray<TabItemOptions | InstrumentAddress>Колонки по порядку, от одной до пятидесяти; голый адрес — стек без графика.
nameнеобязательныйstringДо 64 символов; без него терминал называет вкладку по инструментам.
targetнеобязательныйOpenTargetnew_tab (по умолчанию) или new_window.
windowIdнеобязательныйnumberОкно для новой вкладки; без него — окно в фокусе.
activateнеобязательныйbooleanfalse открывает вкладку в фоне; новое окно всегда получает фокус.

addStacks()

addStacks(options: AddStacksOptions): Promise<WorkspaceOutcome>

POST /v1/workspace/windows/{id}/tabs/{tab}/stacks (workspace:write): те же колонки после последней колонки вкладки; вкладка сохраняет имя и ширины колонок. Ответ перечисляет только добавленные виджеты.

Операция HTTP: POST /v1/workspace/windows/{id}/tabs/{tab}/stacks

ОпцииТипОписание
windowIdnumber
tabIdnumber
itemsArray<TabItemOptions | InstrumentAddress>Колонки по порядку, от одной до пятидесяти; голый адрес — стек без графика.

openMultiview()

openMultiview(options: OpenMultiviewOptions): Promise<WorkspaceOutcome>

POST /v1/workspace/multiview (workspace:write): монета на каждой площадке из «Раскладки бирж», тот же план, что у кнопки «Мультивью» в окне. Нет ни одной ячейки для монеты — not_found.

Операция HTTP: POST /v1/workspace/multiview

ОпцииТипОписание
basestringМонета (BTC) или пара (BTC/USDT).
targetнеобязательныйOpenTargetБез него решает настройка мультивью «Открывать».
windowIdнеобязательныйnumber
activateнеобязательныйboolean

setStackInstrument()

setStackInstrument(options: StackInstrumentOptions): Promise<WorkspaceOutcome>

PATCH /v1/workspace/stacks/{widget_id} (workspace:write): другой инструмент в стеке и его графиках.

Операция HTTP: PATCH /v1/workspace/stacks/{widget_id}

ОпцииТипОписание
widgetIdnumber
instrumentInstrumentAddress
connectionIdнеобязательныйnumber

closeStack()

closeStack(options: StackOptions): Promise<WorkspaceOutcome>

DELETE /v1/workspace/stacks/{widget_id} (workspace:write): закрыть один стек, как это делает его кнопка закрытия.

Операция HTTP: DELETE /v1/workspace/stacks/{widget_id}

ОпцииТипОписание
widgetIdnumber

closeTab()

closeTab(options: TabOptions): Promise<WorkspaceOutcome>

DELETE /v1/workspace/windows/{id}/tabs/{tab} (workspace:write): единственная вкладка окна — invalid_request.

Операция HTTP: DELETE /v1/workspace/windows/{id}/tabs/{tab}

ОпцииТипОписание
windowIdnumber
tabIdnumber

activateTab()

activateTab(options: TabOptions): Promise<WorkspaceOutcome>

POST /v1/workspace/windows/{id}/tabs/{tab}/activate (workspace:write): выбрать вкладку; фокус окна не трогается.

Операция HTTP: POST /v1/workspace/windows/{id}/tabs/{tab}/activate

ОпцииТипОписание
windowIdnumber
tabIdnumber

closeWindow()

closeWindow(options: WindowOptions): Promise<WorkspaceOutcome>

DELETE /v1/workspace/windows/{id} (workspace:write): главное окно — invalid_request.

Операция HTTP: DELETE /v1/workspace/windows/{id}

ОпцииТипОписание
windowIdnumber

activateWindow()

activateWindow(options: WindowOptions): Promise<WorkspaceOutcome>

POST /v1/workspace/windows/{id}/activate (workspace:write): развернуть, если свёрнуто, и вывести на передний план.

Операция HTTP: POST /v1/workspace/windows/{id}/activate

ОпцииТипОписание
windowIdnumber

settings()

settings(options: SettingsOptions = {}): Promise<Settings>

GET /v1/settings (settings:read): строки, как они хранятся, без лестницы умолчаний. Без параметров: глобальные строки без подключения. Каждая строка говорит, пишется ли она (writable) через updateSettings.

Операция HTTP: GET /v1/settings

ОпцииТипОписание
scopeнеобязательный"global" | "order_book"global (по умолчанию) или order_book.
categoryнеобязательныйstring
keyнеобязательныйstring
connectionIdнеобязательныйnumberСтроки подключения; без него — строки без подключения.
instrumentнеобязательныйInstrumentAddressСтроки пары (область order_book).

orderbookSettings()

orderbookSettings(options: InstrumentCommandOptions): Promise<OrderbookSettings>

GET /v1/settings/orderbook (settings:read): настройки стека инструмента, как их видит его стек на подключении, — строка пары, умолчание подключения, строка пары без подключения, глобальное умолчание — с resolved_from у каждого ключа.

Операция HTTP: GET /v1/settings/orderbook

ОпцииТипОписание
connectionIdnumber
instrumentInstrumentAddress

updateSettings()

updateSettings(changes: SettingChange[]): Promise<SettingsApplied>

PATCH /v1/settings (settings:write): записать настройки так, как это делает Settings App. Каждое изменение сначала проверяется по словарю терминала (invalid_request с указанием changes[i], ничего не записано; плечо здесь unsupported — используйте setLeverage), затем они применяются по порядку: та же строка, событие окну и кэши сервисов, что у Settings App. Первое неудавшееся изменение отклоняет вызов; предыдущие остаются применёнными.

Операция HTTP: PATCH /v1/settings

stream()

stream(options: StreamOptions = {}): Promise<Stream>

Открыть /v1/stream. Только в Node: токен передаётся в заголовке рукопожатия.

ОпцииТипОписание
timeoutMsнеобязательныйnumberТаймаут рукопожатия; по умолчанию — timeoutMs клиента.

StreamProtocol

Половина протокола стрима без сокета: выдаёт идентификаторы запросов, держит запросы, ждущие ответа, разрешает их по кадрам subscribed / unsubscribed / error и превращает всё остальное в кадры, по которым итерируется потребитель. Чистая, поэтому тестируется без сервера.

nextRequestId()

nextRequestId(): string

Новый request_id, уникальный в пределах этого стрима.

expect()

expect(requestId: string): Promise<ReplyFrame>

Зарегистрировать запрос и получить промис, который разрешит его ответ.

pendingCount

pendingCount: number

Запросы, всё ещё ждущие ответа.

route()

route(raw: unknown): StreamFrame | undefined

Классифицировать декодированный кадр. Ответы на наши запросы разрешают соответствующий промис и возвращают undefined; event, gap и ошибки подписок возвращаются потребителю; всё неизвестное или искажённое отбрасывается.

abortAll()

abortAll(error: Error): void

Отклонить все ждущие запросы, например при закрытии сокета.

Stream

class Stream extends AsyncIterable<StreamFrame>

Живое соединение /v1/stream.

Получите его через terminal.stream(). Подпишитесь через subscribe, затем итерируйтесь: for await (const frame of stream) отдаёт события, пропуски и ошибки подписок в порядке прихода, буферизуя их без ограничения, пока потребитель занят (сервер защищает себя сам: клиент, отстающий дольше 5 с, закрывается с 4008). Итерируется один потребитель за раз; второй одновременный next() просто ждёт своей очереди.

Когда соединение закрывает сервер, итерация заканчивается; для 1001, 4008, 4029 и потерянного соединения (1006) она заканчивается исключением StreamClosedError. closeCode и closeReason заполняются в любом случае. Закрытие со стороны клиента (close или break из цикла) завершает итерацию штатно.

connect()

static connect(options: StreamConnectOptions): Promise<Stream>

Открыть WebSocket и пройти рукопожатие. Отклоняется с TerminalUnreachableError, когда терминал его не принимает: WebSocket в Node сообщает об отклонённом рукопожатии (терминал не запущен, API выключен, токен отклонён) одной общей ошибкой, поэтому три случая не различаются.

ОпцииТипОписание
urlstringws://127.0.0.1:48180/v1/stream.
tokenstring
timeoutMsнеобязательныйnumberТаймаут рукопожатия; по умолчанию 10 000.

url

url: string

URL стрима (токена в нём нет никогда).

closed

closed: boolean

true, как только сокет закрыт, кем бы он ни был закрыт.

closeCode

closeCode: number | undefined

Код закрытия WebSocket, после закрытия.

closeReason

closeReason: string | undefined

Причина закрытия WebSocket, после закрытия.

subscribe()

subscribe(options: SubscribeOptions): Promise<Subscribed>

Подписаться на топик инструмента или на топик счёта подключения. Разрешается кадром subscribed сервера (плюс запрошенный topic и, для рыночных топиков, instrument) и отклоняется с StreamRequestError на ответ error сервера; события других подписок тем временем идут дальше. Помните о лимите терминала на новые подписки на биржах в секунду (/v1/meta); топики счёта биржу не трогают и кадра-снимка не шлют — сначала прочитайте текущее состояние операциями /v1/account/*.

ОпцииТипОписание
topicTopic
instrumentнеобязательныйInstrumentAddressОбязателен для рыночных топиков; игнорируется для account.*.
connectionIdнеобязательныйnumberОбязателен для account.*; для рыночных топиков без него выбирается по общему правилу.
paramsнеобязательныйBookTopParamsЧитает их только book.top; имена как на проводе (depth, interval_ms).

unsubscribe()

unsubscribe(subscription: Subscribed | SubscribedFrame | string): Promise<void>

Снять подписку сразу. Принимает значение, которым разрешился subscribe, или голый id sub. Разрешается на unsubscribed сервера.

close()

close(code: number = CLOSE_NORMAL, reason?: string): Promise<void>

Закрыть стрим. Сервер завершает рукопожатие закрытия кодом клиента; промис разрешается, когда это произошло, или после короткой паузы, если этого так и не случилось. Повторный вызов безопасен.

Поиск терминала

КонстантыЗначениеОписание
DEFAULT_PORT48180Порт, который слушает терминал, если его не переопределяет SPECTRE_LOCAL_API_PORT.
TOKEN_ENV"SPECTRE_LOCAL_API_TOKEN"Переменная окружения, из которой читается токен.

instancePath()

function instancePath(options: DiscoveryEnvironment = {}): string

Путь к instance.json терминала по ОС:

  • Linux: $XDG_DATA_HOME/spectre-terminal/instance.json, иначе ~/.local/share/spectre-terminal/instance.json;
  • macOS: ~/Library/Application Support/spectre-terminal/instance.json;
  • Windows: %LOCALAPPDATA%\spectre-terminal\instance.json, иначе %USERPROFILE%\AppData\Local\....

Это повторяет собственный каталог данных терминала (dirs::data_local_dir).

readPort()

function readPort(options: ReadPortOptions = {}): Promise<number | undefined>

Порт Local API, опубликованный в instance.json.

Разрешается в undefined, когда файла нет или он нечитаем (терминал не запущен, или терминал не публикует это поле): вызывающий откатывается на DEFAULT_PORT. Бросает LocalApiDisabledError, когда файл есть, но local_api_port равен null или отсутствует — терминал запущен, а API выключен. Читает только это одно поле.

tokenFromEnv()

function tokenFromEnv(env: Record<string, string | undefined> = process.env): string | undefined

Токен из SPECTRE_LOCAL_API_TOKEN или undefined, если переменная не задана или пуста.

Ошибки

SpectreTerminalError

class SpectreTerminalError extends Error

Базовый класс всех ошибок, которые бросает этот пакет.

ApiError

class ApiError extends SpectreTerminalError

Терминал ответил статусом не 2xx.

code — стабильный код из конверта ошибки контракта (unauthorized, not_found, rate_limited, …); status — HTTP-статус. Тело не 2xx, которое не является конвертом, даёт код "unknown".

ПолеТипОписание
codestringСтабильный код ошибки из контракта или "unknown".
statusnumberHTTP-статус ответа.
detailstringСообщение сервера для человека, без префикса.

TerminalUnreachableError

class TerminalUnreachableError extends SpectreTerminalError

HTTP-ответа нет вовсе: соединение отклонено, запрос истёк по таймауту, неожиданный редирект или рукопожатие WebSocket не завершилось. Исходная ошибка — в cause.

LocalApiDisabledError

class LocalApiDisabledError extends SpectreTerminalError

instance.json есть, но порта Local API в нём нет: терминал запущен с выключенным API, или файл остался от терминала, который завершился нештатно. В любом случае подключаться некуда, пока API не включён в Settings App (Общие → Local API).

TokenMissingError

class TokenMissingError extends SpectreTerminalError

Ни параметр token, ни SPECTRE_LOCAL_API_TOKEN токена не дали.

IncompatibleTerminalError

class IncompatibleTerminalError extends SpectreTerminalError

/v1/meta сообщил версию API, на которой этот клиент не говорит.

ПолеТипОписание
apiVersionstringapi_version, который сообщил терминал.
appVersionstringapp_version, который сообщил терминал.

StreamRequestError

class StreamRequestError extends SpectreTerminalError

Стрим ответил на запрос subscribe или unsubscribe кадром error. code — код ошибки контракта (not_found, rate_limited, invalid_request, …). Остальные подписки идут дальше.

ПолеТипОписание
codestringСтабильный код ошибки из контракта.
detailstringСообщение сервера для человека, без префикса.

StreamClosedError

class StreamClosedError extends SpectreTerminalError

Сервер закрыл стрим по причине, на которую потребитель должен отреагировать: 1001 — API выключен или токен перевыпущен; 4008 — этот клиент читал слишком медленно; 4029 — лимит соединений на токен. Также бросается для 1006, когда соединение оборвалось без кадра закрытия, и из subscribe / unsubscribe на уже закрытом стриме.

ПолеТипОписание
codenumberКод закрытия WebSocket.
reasonstringПричина закрытия, присланная сервером; может быть пустой.

Собрано из кода @spectre-trade/terminal, коммит 2d1c324.

На этой странице