@usherlabs/cex-broker 0.2.37 → 0.2.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/commands/cli.js +2088 -1259
- package/dist/handlers/subscribe/handler.d.ts +2 -0
- package/dist/helpers/binance-user-data-normalization.d.ts +3 -0
- package/dist/helpers/binance-user-data-stream.d.ts +12 -0
- package/dist/helpers/broker-execution-archive/index.d.ts +1 -1
- package/dist/helpers/broker-execution-archive/rows.d.ts +1 -0
- package/dist/helpers/deposit-archive-poller.d.ts +1 -0
- package/dist/helpers/market-data-archive/capture-context.d.ts +24 -3
- package/dist/helpers/market-data-archive/index.d.ts +1 -1
- package/dist/helpers/stream-health-publisher.d.ts +41 -0
- package/dist/helpers/user-data-stream-supervisor.d.ts +27 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2090 -1261
- package/dist/index.js.map +18 -15
- package/dist/server.d.ts +2 -1
- package/package.json +10 -2
|
@@ -2,6 +2,7 @@ import * as grpc from "@grpc/grpc-js";
|
|
|
2
2
|
import { type BrokerPoolEntry } from "../../helpers/broker";
|
|
3
3
|
import type { BrokerExecutionArchiver } from "../../helpers/broker-execution-archive";
|
|
4
4
|
import type { OtelMetrics } from "../../helpers/otel";
|
|
5
|
+
import type { UserDataStreamSupervisor } from "../../helpers/user-data-stream-supervisor";
|
|
5
6
|
import type { SubscribeRequest, SubscribeResponse } from "../types";
|
|
6
7
|
import { SubscribeBrokerLifecycle } from "./broker-lifecycle";
|
|
7
8
|
export type SubscribeDeps = {
|
|
@@ -10,6 +11,7 @@ export type SubscribeDeps = {
|
|
|
10
11
|
otelMetrics?: OtelMetrics;
|
|
11
12
|
brokerArchiver?: BrokerExecutionArchiver;
|
|
12
13
|
brokerLifecycle?: SubscribeBrokerLifecycle;
|
|
14
|
+
userDataStreamSupervisor?: UserDataStreamSupervisor;
|
|
13
15
|
};
|
|
14
16
|
type SubscribeCall = grpc.ServerWritableStream<SubscribeRequest, SubscribeResponse>;
|
|
15
17
|
export declare function createSubscribeHandler(deps: SubscribeDeps): (call: SubscribeCall) => Promise<void>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { Exchange } from "@usherlabs/ccxt";
|
|
2
|
+
export declare function normalizeBinanceSpotBalanceEvent(exchange: Exchange, event: Record<string, unknown>): Promise<unknown>;
|
|
3
|
+
export declare function normalizeBinanceExecutionReport(exchange: Exchange, event: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -5,6 +5,16 @@ export type BinanceUserDataEvent = {
|
|
|
5
5
|
subscriptionId: number;
|
|
6
6
|
event: Record<string, unknown>;
|
|
7
7
|
};
|
|
8
|
+
export type BinanceUserDataStreamFailureKind = "auth_failed" | "transport_error" | "remote_closed" | "protocol_error" | "backpressure";
|
|
9
|
+
export type BinanceUserDataStreamObserver = {
|
|
10
|
+
onConnected?: () => void;
|
|
11
|
+
onAuthenticated?: () => void;
|
|
12
|
+
onEvent?: (event: BinanceUserDataEvent) => void;
|
|
13
|
+
onFailure?: (failure: {
|
|
14
|
+
kind: BinanceUserDataStreamFailureKind;
|
|
15
|
+
reason: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
};
|
|
8
18
|
type WebSocketLike = {
|
|
9
19
|
on(event: "open", listener: () => void): unknown;
|
|
10
20
|
on(event: "message", listener: (data: unknown) => void): unknown;
|
|
@@ -16,6 +26,7 @@ type WebSocketLike = {
|
|
|
16
26
|
type WebSocketFactory = (url: string) => WebSocketLike;
|
|
17
27
|
type BinanceSpotUserDataStreamOptions = {
|
|
18
28
|
maxBufferedEvents?: number;
|
|
29
|
+
observer?: BinanceUserDataStreamObserver;
|
|
19
30
|
};
|
|
20
31
|
export declare function setBinanceUserDataWebSocketFactoryForTests(factory: WebSocketFactory): () => void;
|
|
21
32
|
export declare function getBinanceSpotWsApiUrl(exchange: Exchange): string;
|
|
@@ -25,6 +36,7 @@ export declare class BinanceSpotUserDataStream implements AsyncIterable<BinanceU
|
|
|
25
36
|
private readonly secretValues;
|
|
26
37
|
private readonly requestId;
|
|
27
38
|
private readonly maxBufferedEvents;
|
|
39
|
+
private readonly observer?;
|
|
28
40
|
private readonly queue;
|
|
29
41
|
private readonly waiters;
|
|
30
42
|
private closed;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { archiveOrderExecutionInBackground, archiveSubscribeStreamInBackground, archiveTransferEventInBackground, archiveWithdrawalObservationsInBackground, captureMarketMetadataSnapshot, captureMarketMetadataSnapshotInBackground, } from "./capture";
|
|
2
2
|
export { hashMarketMetadata, redactErrorForArchive, redactSecretLiterals, redactStreamPayload, } from "./redact";
|
|
3
|
-
export { buildAccountBalanceSnapshotRow, buildCommonArchiveTags, buildFillEventArchiveRow, buildMarketMetadataSnapshotRow, buildOrderEventArchiveRow, buildSubscribeStreamArchiveRow, buildTransferEventArchiveRow, extractBinanceInternalTransferId, type FillArchiveFields, type NormalizedCcxtBalance, type NormalizedCcxtTransfer, normalizeCcxtBalanceForArchive, normalizeCcxtTradeForArchive, normalizeCcxtTransactionForArchive, type TransferArchiveFields, } from "./rows";
|
|
3
|
+
export { buildAccountBalanceSnapshotRow, buildCommonArchiveTags, buildFillEventArchiveRow, buildMarketMetadataSnapshotRow, buildOrderEventArchiveRow, buildSubscribeStreamArchiveRow, buildTransferEventArchiveRow, extractBinanceInternalTransferId, type FillArchiveFields, type NormalizedCcxtBalance, type NormalizedCcxtTransfer, normalizeCcxtBalanceForArchive, normalizeCcxtTradeForArchive, normalizeCcxtTransactionForArchive, normalizeTimestamp, type TransferArchiveFields, } from "./rows";
|
|
4
4
|
export { ACCOUNT_BALANCE_PRECISION_BASIS, ACCOUNT_BALANCE_SCOPE, ARCHIVE_SCHEMA_VERSION, BROKER_READ_SOURCE, BROKER_WRITE_SOURCE, type BrokerArchiveCommonTags, type BrokerArchiveRow, type BrokerArchiveSource, type BrokerArchiveTable, type OrderArchiveAction, type SubscribeArchiveType, type TransferEventKind, type TransferLifecycleAction, } from "./types";
|
|
5
5
|
export { DEFAULT_WITHDRAWAL_OBSERVATION_TRACKER_MAX_ENTRIES, WithdrawalObservationTracker, } from "./withdrawal-observation-tracker";
|
|
6
6
|
export { BrokerExecutionArchiveDurabilityError, BrokerExecutionArchiver, type BrokerExecutionArchiverOptions, createBrokerExecutionArchiverFromEnv, isArchiveOtelLogsEnabled, isBrokerExecutionArchiveTable, resolveArchiveForwarderUrlFromEnv, rethrowArchiveDurabilityError, } from "./writer";
|
|
@@ -12,6 +12,7 @@ export type NormalizedCcxtBalance = {
|
|
|
12
12
|
usedMapPresent: boolean;
|
|
13
13
|
totalMapPresent: boolean;
|
|
14
14
|
};
|
|
15
|
+
export declare function normalizeTimestamp(value: unknown): string | undefined;
|
|
15
16
|
export declare function normalizeCcxtBalanceForArchive(balance: unknown): NormalizedCcxtBalance;
|
|
16
17
|
export declare function buildAccountBalanceSnapshotRow(input: {
|
|
17
18
|
tags: BrokerArchiveCommonTags;
|
|
@@ -16,10 +16,31 @@ export declare function createMarketCaptureContext(input: {
|
|
|
16
16
|
accountSelector?: string;
|
|
17
17
|
environment?: CaptureEnvironment;
|
|
18
18
|
}): MarketCaptureContext;
|
|
19
|
-
export
|
|
20
|
-
|
|
19
|
+
export type MarketCaptureArchiveDisabledReason = "archive_disabled" | "market_archive_disabled" | "invalid_capture_environment" | "missing_deployment_id" | "missing_capture_bundle_id";
|
|
20
|
+
export type MarketCaptureArchiveState = {
|
|
21
|
+
enabled: true;
|
|
22
|
+
} | {
|
|
23
|
+
enabled: false;
|
|
24
|
+
reason: MarketCaptureArchiveDisabledReason;
|
|
25
|
+
};
|
|
26
|
+
export declare function resolveMarketCaptureArchiveState(input: {
|
|
27
|
+
archiveEnabled: boolean;
|
|
28
|
+
marketArchiveEnabled: boolean;
|
|
29
|
+
environment?: string;
|
|
30
|
+
deploymentId?: string;
|
|
21
31
|
captureBundleId?: string;
|
|
22
|
-
}):
|
|
32
|
+
}): MarketCaptureArchiveState;
|
|
33
|
+
/**
|
|
34
|
+
* Throws when archival was requested but its capture identity is incomplete.
|
|
35
|
+
*
|
|
36
|
+
* `archive_disabled` and `market_archive_disabled` are deliberate opt-outs and
|
|
37
|
+
* must keep the broker available — that is the whole point of resolving to a
|
|
38
|
+
* typed state instead of throwing. Every other disabled reason means archival
|
|
39
|
+
* was asked for and cannot be honoured, which is a misconfiguration: a broker
|
|
40
|
+
* started in that state serves RPC and passes health while writing no
|
|
41
|
+
* market-data row at all, and the only trace is one line at boot.
|
|
42
|
+
*/
|
|
43
|
+
export declare function assertMarketCaptureArchiveStartable(state: MarketCaptureArchiveState): void;
|
|
23
44
|
export declare function validateExternalFallbackContext(input: {
|
|
24
45
|
configuredExchange: string;
|
|
25
46
|
configuredSymbol: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { buildCanonicalOrderBookRows, OrderBookValidationError, } from "./canonical-orderbook";
|
|
2
2
|
export { archiveCexStreamEventInBackground, archiveOhlcvInBackground, archiveOrderbookInBackground, archiveOrderbookSnapshotInBackground, archiveOrderbookTobInBackground, archiveTickerInBackground, archiveTradesInBackground, createOhlcvBarTracker, createOrderbookSampler, createOrderbookTobSampler, } from "./capture";
|
|
3
|
-
export { captureEnvironmentFromEnv, createMarketCaptureContext,
|
|
3
|
+
export { assertMarketCaptureArchiveStartable, captureEnvironmentFromEnv, createMarketCaptureContext, type MarketCaptureArchiveDisabledReason, type MarketCaptureArchiveState, resolveMarketCaptureArchiveState, validateExternalFallbackContext, } from "./capture-context";
|
|
4
4
|
export { ARCHIVE_SOURCES, CAPTURE_FEEDS, CHECKSUM_ALGORITHM, CONSTRUCTION_MODES, canonicalDecimal, canonicalSerialize, createRawCapture, GAP_POLICIES, MARKET_CAPTURE_SCHEMA_VERSION, RAW_CAPTURE_SCOPES, SOURCE_MODES, sha256Canonical, } from "./capture-contract";
|
|
5
5
|
export { buildLegacyOhlcvMigrationRow, buildLegacyOrderBookMigrationRows, type LegacyCandle, type LegacyOrderBookSnapshot, } from "./legacy-migration";
|
|
6
6
|
export { extractLatestOhlcvBar, extractOhlcvBars, OhlcvBarTracker, parseOhlcvBar, } from "./ohlcv-bar-tracker";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type StreamHealthState = "connecting" | "connected" | "disconnected" | "error";
|
|
2
|
+
export type StreamHealthFailureKind = "none" | "auth_failed" | "transport_error" | "remote_closed" | "protocol_error" | "backpressure" | "unsupported_connector" | "shutdown";
|
|
3
|
+
export type StreamHealthSnapshot = {
|
|
4
|
+
exchange: string;
|
|
5
|
+
accountSelector: string;
|
|
6
|
+
accountRole?: string;
|
|
7
|
+
streamKind: "user_data";
|
|
8
|
+
accountScope: "spot";
|
|
9
|
+
registryStatus: "active" | "retired";
|
|
10
|
+
retiredAt: string | null;
|
|
11
|
+
state: StreamHealthState;
|
|
12
|
+
stateChangedAt: string;
|
|
13
|
+
lastConnectedAt: string | null;
|
|
14
|
+
lastAuthenticatedAt: string | null;
|
|
15
|
+
lastReceivedAt: string | null;
|
|
16
|
+
connectAttemptCount: string;
|
|
17
|
+
reconnectCount: string;
|
|
18
|
+
errorCount: string;
|
|
19
|
+
lastFailureKind: StreamHealthFailureKind;
|
|
20
|
+
lastFailureReason: string;
|
|
21
|
+
trafficMode: "event_driven" | "continuous" | "unknown";
|
|
22
|
+
sourceWatermark: string | null;
|
|
23
|
+
};
|
|
24
|
+
export type StreamHealthPublisherOptions = {
|
|
25
|
+
deploymentId: string;
|
|
26
|
+
statePath: string;
|
|
27
|
+
forwarderUrl: string;
|
|
28
|
+
forwarderAuthToken?: string;
|
|
29
|
+
heartbeatIntervalMs?: number;
|
|
30
|
+
forwarderTimeoutMs?: number;
|
|
31
|
+
post?: (body: string) => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
/** A whole health batch is persisted before POST so retries are exact replays. */
|
|
34
|
+
export declare class StreamHealthPublisher {
|
|
35
|
+
#private;
|
|
36
|
+
constructor(options: StreamHealthPublisherOptions);
|
|
37
|
+
start(): void;
|
|
38
|
+
publish(snapshots: readonly StreamHealthSnapshot[]): void;
|
|
39
|
+
close(snapshots: readonly StreamHealthSnapshot[], timeoutMs?: number): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export declare function streamHealthPublisherConfigFromEnv(env?: NodeJS.ProcessEnv): StreamHealthPublisherOptions;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type BinanceUserDataEvent } from "./binance-user-data-stream";
|
|
2
|
+
import type { BrokerPoolEntry } from "./broker";
|
|
3
|
+
import type { StreamHealthPublisher } from "./stream-health-publisher";
|
|
4
|
+
export type UserDataSubscriptionKind = "balance" | "orders";
|
|
5
|
+
export type UserDataSubscription = AsyncIterable<BinanceUserDataEvent> & {
|
|
6
|
+
close(): void;
|
|
7
|
+
};
|
|
8
|
+
export type UserDataStreamSupervisorOptions = {
|
|
9
|
+
brokers: Record<string, BrokerPoolEntry>;
|
|
10
|
+
publisher: StreamHealthPublisher;
|
|
11
|
+
};
|
|
12
|
+
type UserDataSubscriptionOptions = {
|
|
13
|
+
exchange: string;
|
|
14
|
+
accountSelector: string;
|
|
15
|
+
kind: UserDataSubscriptionKind;
|
|
16
|
+
marketId?: string;
|
|
17
|
+
};
|
|
18
|
+
/** Owns one physical authenticated venue stream for each configured account. */
|
|
19
|
+
export declare class UserDataStreamSupervisor {
|
|
20
|
+
#private;
|
|
21
|
+
private readonly options;
|
|
22
|
+
constructor(options: UserDataStreamSupervisorOptions);
|
|
23
|
+
start(): void;
|
|
24
|
+
subscribe(options: UserDataSubscriptionOptions): UserDataSubscription;
|
|
25
|
+
close(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export default class CEXBroker {
|
|
|
18
18
|
private fillArchivePoller?;
|
|
19
19
|
private depositArchivePoller?;
|
|
20
20
|
private accountBalanceArchivePoller?;
|
|
21
|
+
private userDataStreamSupervisor?;
|
|
21
22
|
/**
|
|
22
23
|
* Loads environment variables prefixed with CEX_BROKER_
|
|
23
24
|
* Expected format:
|