@usherlabs/cex-broker 0.2.48 → 0.2.50
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/dist/commands/cex-canonical-orderbook-export.js +72 -358
- package/dist/commands/cex-canonical-orderbook-export.js.map +7 -19
- package/dist/commands/cli.js +224 -67
- package/dist/commands/market-data-vendor-backfill.js +975 -1198
- package/dist/commands/market-data-vendor-backfill.js.map +13 -25
- package/dist/helpers/logger.d.ts +4 -0
- package/dist/helpers/market-data-vendor-backfill/cryptohftdata.d.ts +3 -1
- package/dist/helpers/market-data-vendor-backfill/manifests.d.ts +58 -4
- package/dist/helpers/market-data-vendor-backfill/semantic-verification.d.ts +1 -0
- package/dist/helpers/otel.d.ts +1 -0
- package/dist/helpers/trace-context.d.ts +8 -0
- package/dist/index.js +183 -63
- package/dist/index.js.map +9 -8
- package/dist/market-data-preparation/fixtures/conformance-v2.json +8 -8
- package/dist/market-data-preparation/policies/capability-policy-v1.json +28 -0
- package/dist/market-data-preparation/policies/capability-policy.json +14 -3
- package/dist/market-data-preparation/policies/resource-policy-v1.json +16 -0
- package/dist/market-data-preparation/policies/resource-policy.json +3 -3
- package/dist/market-data-preparation.js +70 -359
- package/dist/market-data-preparation.js.map +9 -21
- package/dist/market-data-vendor-backfill/policies/capability-policy-v2.json +39 -0
- package/dist/market-data-vendor-backfill/policies/resource-policy-v2.json +16 -0
- package/dist/market-data-vendor-backfill.d.ts +2 -2
- package/dist/market-data-vendor-backfill.js +1528 -1750
- package/dist/market-data-vendor-backfill.js.map +13 -25
- package/package.json +1 -1
package/dist/commands/cli.js
CHANGED
|
@@ -313534,16 +313534,20 @@ var tslogLogger = new Logger({
|
|
|
313534
313534
|
minLevel: process.env.LOG_LEVEL === "debug" ? 0 : 3
|
|
313535
313535
|
});
|
|
313536
313536
|
var baseLogger = new LogLayer({
|
|
313537
|
-
transport: [
|
|
313538
|
-
new TsLogTransport({ id: "tslog", logger: tslogLogger }),
|
|
313539
|
-
new OpenTelemetryTransport({
|
|
313540
|
-
id: "otel",
|
|
313541
|
-
enabled: true
|
|
313542
|
-
})
|
|
313543
|
-
],
|
|
313537
|
+
transport: [new TsLogTransport({ id: "tslog", logger: tslogLogger })],
|
|
313544
313538
|
plugins: [openTelemetryPlugin()],
|
|
313545
313539
|
errorSerializer: serializeError
|
|
313546
313540
|
});
|
|
313541
|
+
var OTEL_TRANSPORT_ID = "otel";
|
|
313542
|
+
function attachOtelLogTransport() {
|
|
313543
|
+
baseLogger.addTransport(new OpenTelemetryTransport({
|
|
313544
|
+
id: OTEL_TRANSPORT_ID,
|
|
313545
|
+
enabled: true
|
|
313546
|
+
}));
|
|
313547
|
+
}
|
|
313548
|
+
function detachOtelLogTransport() {
|
|
313549
|
+
baseLogger.removeTransport(OTEL_TRANSPORT_ID);
|
|
313550
|
+
}
|
|
313547
313551
|
if (process.env.LOG_LEVEL !== "debug") {
|
|
313548
313552
|
baseLogger.setLevel("info");
|
|
313549
313553
|
}
|
|
@@ -317970,11 +317974,14 @@ var import_sdk_metrics = __toESM(require_src12(), 1);
|
|
|
317970
317974
|
var DEFAULT_SERVICE = "cex-broker";
|
|
317971
317975
|
var DEFAULT_OTLP_PORT = 4318;
|
|
317972
317976
|
var EXPORT_INTERVAL_MS = 5000;
|
|
317977
|
+
var EXPORT_TIMEOUT_MS = 2000;
|
|
317978
|
+
var SHUTDOWN_TIMEOUT_MS = 3000;
|
|
317973
317979
|
|
|
317974
317980
|
class BaseOtelSignal {
|
|
317975
317981
|
signal;
|
|
317976
317982
|
provider = null;
|
|
317977
317983
|
isEnabled = false;
|
|
317984
|
+
closePromise = null;
|
|
317978
317985
|
serviceName;
|
|
317979
317986
|
constructor(config, signal) {
|
|
317980
317987
|
this.signal = signal;
|
|
@@ -318006,19 +318013,35 @@ class BaseOtelSignal {
|
|
|
318006
318013
|
isOtelEnabled() {
|
|
318007
318014
|
return this.isEnabled && this.provider !== null;
|
|
318008
318015
|
}
|
|
318009
|
-
|
|
318010
|
-
if (
|
|
318011
|
-
return;
|
|
318012
|
-
|
|
318013
|
-
try {
|
|
318014
|
-
await this.shutdownProvider(this.provider);
|
|
318015
|
-
log.info(`OTel ${this.signal} provider shut down`);
|
|
318016
|
-
} catch (error) {
|
|
318017
|
-
log.error(`Error shutting down OTel ${this.signal} provider:`, error);
|
|
318018
|
-
}
|
|
318016
|
+
close() {
|
|
318017
|
+
if (this.closePromise)
|
|
318018
|
+
return this.closePromise;
|
|
318019
|
+
const provider = this.provider;
|
|
318019
318020
|
this.provider = null;
|
|
318020
318021
|
this.isEnabled = false;
|
|
318021
318022
|
this.onProviderClosed();
|
|
318023
|
+
if (!provider) {
|
|
318024
|
+
this.closePromise = Promise.resolve();
|
|
318025
|
+
return this.closePromise;
|
|
318026
|
+
}
|
|
318027
|
+
const shutdown = Promise.resolve().then(() => this.shutdownProvider(provider)).then(() => {
|
|
318028
|
+
log.info(`OTel ${this.signal} provider shut down`);
|
|
318029
|
+
}, (error) => {
|
|
318030
|
+
log.error(`Error shutting down OTel ${this.signal} provider:`, error);
|
|
318031
|
+
});
|
|
318032
|
+
let deadlineTimer;
|
|
318033
|
+
const deadline = new Promise((resolve) => {
|
|
318034
|
+
deadlineTimer = setTimeout(() => {
|
|
318035
|
+
deadlineTimer = undefined;
|
|
318036
|
+
log.warn(`OTel ${this.signal} provider shutdown exceeded ${SHUTDOWN_TIMEOUT_MS}ms; continuing shutdown`);
|
|
318037
|
+
resolve();
|
|
318038
|
+
}, SHUTDOWN_TIMEOUT_MS);
|
|
318039
|
+
});
|
|
318040
|
+
this.closePromise = Promise.race([shutdown, deadline]).finally(() => {
|
|
318041
|
+
if (deadlineTimer !== undefined)
|
|
318042
|
+
clearTimeout(deadlineTimer);
|
|
318043
|
+
});
|
|
318044
|
+
return this.closePromise;
|
|
318022
318045
|
}
|
|
318023
318046
|
}
|
|
318024
318047
|
function toAttributes(labels, service) {
|
|
@@ -318041,11 +318064,13 @@ class OtelMetrics extends BaseOtelSignal {
|
|
|
318041
318064
|
}
|
|
318042
318065
|
createProvider(endpoint, serviceName, appendSignalPath) {
|
|
318043
318066
|
const exporter = new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
|
318044
|
-
url: appendOtlpPath(endpoint, "metrics", appendSignalPath)
|
|
318067
|
+
url: appendOtlpPath(endpoint, "metrics", appendSignalPath),
|
|
318068
|
+
timeoutMillis: EXPORT_TIMEOUT_MS
|
|
318045
318069
|
});
|
|
318046
318070
|
const reader = new import_sdk_metrics.PeriodicExportingMetricReader({
|
|
318047
318071
|
exporter,
|
|
318048
|
-
exportIntervalMillis: EXPORT_INTERVAL_MS
|
|
318072
|
+
exportIntervalMillis: EXPORT_INTERVAL_MS,
|
|
318073
|
+
exportTimeoutMillis: EXPORT_TIMEOUT_MS
|
|
318049
318074
|
});
|
|
318050
318075
|
const resource = import_resources.resourceFromAttributes({
|
|
318051
318076
|
"service.name": serviceName
|
|
@@ -318166,15 +318191,23 @@ class OtelMetrics extends BaseOtelSignal {
|
|
|
318166
318191
|
}
|
|
318167
318192
|
|
|
318168
318193
|
class OtelLogs extends BaseOtelSignal {
|
|
318169
|
-
logger
|
|
318194
|
+
logger;
|
|
318170
318195
|
constructor(config) {
|
|
318171
318196
|
super(config, "logs");
|
|
318197
|
+
const provider = this.getProvider();
|
|
318198
|
+
this.logger = provider?.getLogger("cex-broker-logs", "1.0.0") ?? null;
|
|
318199
|
+
if (provider) {
|
|
318200
|
+
attachOtelLogTransport();
|
|
318201
|
+
}
|
|
318172
318202
|
}
|
|
318173
318203
|
createProvider(endpoint, serviceName, appendSignalPath) {
|
|
318174
318204
|
const exporter = new import_exporter_logs_otlp_http.OTLPLogExporter({
|
|
318175
|
-
url: appendOtlpPath(endpoint, "logs", appendSignalPath)
|
|
318205
|
+
url: appendOtlpPath(endpoint, "logs", appendSignalPath),
|
|
318206
|
+
timeoutMillis: EXPORT_TIMEOUT_MS
|
|
318207
|
+
});
|
|
318208
|
+
const processor = new import_sdk_logs.BatchLogRecordProcessor(exporter, {
|
|
318209
|
+
exportTimeoutMillis: EXPORT_TIMEOUT_MS
|
|
318176
318210
|
});
|
|
318177
|
-
const processor = new import_sdk_logs.BatchLogRecordProcessor(exporter);
|
|
318178
318211
|
const resource = import_resources.resourceFromAttributes({
|
|
318179
318212
|
"service.name": serviceName
|
|
318180
318213
|
});
|
|
@@ -318185,12 +318218,12 @@ class OtelLogs extends BaseOtelSignal {
|
|
|
318185
318218
|
}
|
|
318186
318219
|
onProviderCreated(provider) {
|
|
318187
318220
|
import_api_logs3.logs.setGlobalLoggerProvider(provider);
|
|
318188
|
-
this.logger = provider.getLogger("cex-broker-logs", "1.0.0");
|
|
318189
318221
|
}
|
|
318190
318222
|
shutdownProvider(provider) {
|
|
318191
|
-
return provider.
|
|
318223
|
+
return provider.shutdown();
|
|
318192
318224
|
}
|
|
318193
318225
|
onProviderClosed() {
|
|
318226
|
+
detachOtelLogTransport();
|
|
318194
318227
|
this.logger = null;
|
|
318195
318228
|
}
|
|
318196
318229
|
emit(record) {
|
|
@@ -335121,6 +335154,24 @@ function selectBrokerAccountForCex(normalizedCex, brokers, metadata) {
|
|
|
335121
335154
|
return selectBrokerAccount(brokers[normalizedCex], metadata) ?? undefined;
|
|
335122
335155
|
}
|
|
335123
335156
|
|
|
335157
|
+
// src/helpers/trace-context.ts
|
|
335158
|
+
var TRACE_METADATA_KEY = "x-trace-id";
|
|
335159
|
+
var MAX_TRACE_METADATA_LENGTH = 128;
|
|
335160
|
+
var OTEL_TRACE_ID_PATTERN = /^[0-9a-f]{32}$/;
|
|
335161
|
+
var UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
335162
|
+
var ZERO_OTEL_TRACE_ID = "00000000000000000000000000000000";
|
|
335163
|
+
function extractTraceId(metadata) {
|
|
335164
|
+
const raw = metadata.get(TRACE_METADATA_KEY)[0];
|
|
335165
|
+
if (typeof raw !== "string" || raw.length > MAX_TRACE_METADATA_LENGTH) {
|
|
335166
|
+
return;
|
|
335167
|
+
}
|
|
335168
|
+
const traceId = raw.trim();
|
|
335169
|
+
if (OTEL_TRACE_ID_PATTERN.test(traceId) && traceId !== ZERO_OTEL_TRACE_ID || UUID_V4_PATTERN.test(traceId)) {
|
|
335170
|
+
return traceId;
|
|
335171
|
+
}
|
|
335172
|
+
return;
|
|
335173
|
+
}
|
|
335174
|
+
|
|
335124
335175
|
// src/handlers/execute-action/order-book-call.ts
|
|
335125
335176
|
var grpc4 = __toESM(require_src3(), 1);
|
|
335126
335177
|
async function handleOrderBookCall(ctx) {
|
|
@@ -336424,6 +336475,15 @@ function isPublicMarketDataAction(action, payload) {
|
|
|
336424
336475
|
return false;
|
|
336425
336476
|
return isOrderBookCallMethod(payload?.method ?? payload?.functionName);
|
|
336426
336477
|
}
|
|
336478
|
+
function grpcStatusName(error48) {
|
|
336479
|
+
if (!error48) {
|
|
336480
|
+
return "OK";
|
|
336481
|
+
}
|
|
336482
|
+
if (typeof error48.code !== "number") {
|
|
336483
|
+
return "UNKNOWN";
|
|
336484
|
+
}
|
|
336485
|
+
return grpc12.status[error48.code] ?? "UNKNOWN";
|
|
336486
|
+
}
|
|
336427
336487
|
function createExecuteActionHandler(deps) {
|
|
336428
336488
|
const {
|
|
336429
336489
|
policy,
|
|
@@ -336440,12 +336500,28 @@ function createExecuteActionHandler(deps) {
|
|
|
336440
336500
|
const startTime = Date.now();
|
|
336441
336501
|
const { action: rawAction, cex: cex3, symbol: symbol2 } = call.request;
|
|
336442
336502
|
const action = resolveAction(rawAction);
|
|
336503
|
+
const actionName = getActionName(action);
|
|
336504
|
+
const operationalCex = cex3?.trim().toLowerCase() || "unknown";
|
|
336505
|
+
const traceId = extractTraceId(call.metadata);
|
|
336506
|
+
const traceFields = traceId === undefined ? {} : { trace_id: traceId };
|
|
336443
336507
|
let actionCompleted = false;
|
|
336444
336508
|
const wrappedCallback = (error48, value) => {
|
|
336445
336509
|
if (!actionCompleted) {
|
|
336446
336510
|
actionCompleted = true;
|
|
336447
336511
|
const latency = Date.now() - startTime;
|
|
336448
|
-
const
|
|
336512
|
+
const terminalFields = {
|
|
336513
|
+
action: actionName,
|
|
336514
|
+
cex: operationalCex,
|
|
336515
|
+
latency_ms: latency,
|
|
336516
|
+
outcome: error48 ? "error" : "success",
|
|
336517
|
+
grpc_status: grpcStatusName(error48),
|
|
336518
|
+
...traceFields
|
|
336519
|
+
};
|
|
336520
|
+
if (error48) {
|
|
336521
|
+
log.withMetadata(terminalFields).error("ExecuteAction failed");
|
|
336522
|
+
} else {
|
|
336523
|
+
log.withMetadata(terminalFields).info("ExecuteAction completed");
|
|
336524
|
+
}
|
|
336449
336525
|
otelMetrics?.recordHistogram("execute_action_duration_ms", latency, {
|
|
336450
336526
|
action: actionName,
|
|
336451
336527
|
cex: cex3 || "unknown"
|
|
@@ -336466,9 +336542,13 @@ function createExecuteActionHandler(deps) {
|
|
|
336466
336542
|
callback(error48, value);
|
|
336467
336543
|
};
|
|
336468
336544
|
try {
|
|
336469
|
-
log.
|
|
336545
|
+
log.withMetadata({
|
|
336546
|
+
action: actionName,
|
|
336547
|
+
cex: operationalCex,
|
|
336548
|
+
...traceFields
|
|
336549
|
+
}).info("ExecuteAction started");
|
|
336470
336550
|
otelMetrics?.recordCounter("execute_action_requests_total", 1, {
|
|
336471
|
-
action:
|
|
336551
|
+
action: actionName,
|
|
336472
336552
|
cex: cex3 || "unknown"
|
|
336473
336553
|
});
|
|
336474
336554
|
if (!authenticateRequest(call, whitelistIps)) {
|
|
@@ -336706,6 +336786,9 @@ async function writeSubscribeError(call, isClosed, frame) {
|
|
|
336706
336786
|
call.end();
|
|
336707
336787
|
}
|
|
336708
336788
|
}
|
|
336789
|
+
function grpcStatusName2(status14) {
|
|
336790
|
+
return typeof status14 === "number" ? grpc13.status[status14] ?? "UNKNOWN" : "UNKNOWN";
|
|
336791
|
+
}
|
|
336709
336792
|
function getBinanceEventMarketId(event) {
|
|
336710
336793
|
const value = event.s;
|
|
336711
336794
|
return typeof value === "string" ? value : null;
|
|
@@ -336838,6 +336921,24 @@ function createSubscribeHandler(deps) {
|
|
|
336838
336921
|
});
|
|
336839
336922
|
return async (call) => {
|
|
336840
336923
|
const subscribeStartTime = Date.now();
|
|
336924
|
+
const request = call.request;
|
|
336925
|
+
const { cex: cex3, symbol: symbol2, type: type2 } = request;
|
|
336926
|
+
const metadata = call.metadata;
|
|
336927
|
+
const traceId = extractTraceId(metadata);
|
|
336928
|
+
const traceFields = traceId === undefined ? {} : { trace_id: traceId };
|
|
336929
|
+
const operationalCex = cex3?.trim().toLowerCase() || "unknown";
|
|
336930
|
+
const operationalSymbol = symbol2?.trim() || "unknown";
|
|
336931
|
+
const subscriptionType2 = resolveSubscriptionType(type2);
|
|
336932
|
+
const subscriptionTypeName = getSubscriptionTypeName(subscriptionType2);
|
|
336933
|
+
const operationalFields = {
|
|
336934
|
+
cex: operationalCex,
|
|
336935
|
+
symbol: operationalSymbol,
|
|
336936
|
+
subscription_type: subscriptionTypeName,
|
|
336937
|
+
...traceFields
|
|
336938
|
+
};
|
|
336939
|
+
let terminalLogged = false;
|
|
336940
|
+
let terminalOutcome = "completed";
|
|
336941
|
+
let terminalGrpcStatus = "OK";
|
|
336841
336942
|
let streamClosed = false;
|
|
336842
336943
|
let ownedBroker = null;
|
|
336843
336944
|
let ownedBrokerClosePromise;
|
|
@@ -336860,12 +336961,41 @@ function createSubscribeHandler(deps) {
|
|
|
336860
336961
|
const closeOwnedBrokerOnCallEnd = () => {
|
|
336861
336962
|
closeOwnedBroker();
|
|
336862
336963
|
};
|
|
336863
|
-
|
|
336964
|
+
const logTerminalOutcome = (outcome) => {
|
|
336965
|
+
if (terminalLogged) {
|
|
336966
|
+
return;
|
|
336967
|
+
}
|
|
336968
|
+
terminalLogged = true;
|
|
336969
|
+
const fields = {
|
|
336970
|
+
...operationalFields,
|
|
336971
|
+
duration_ms: Date.now() - subscribeStartTime,
|
|
336972
|
+
outcome,
|
|
336973
|
+
grpc_status: outcome === "cancelled" ? "CANCELLED" : terminalGrpcStatus
|
|
336974
|
+
};
|
|
336975
|
+
if (outcome === "error") {
|
|
336976
|
+
log.withMetadata(fields).error("Subscribe failed");
|
|
336977
|
+
} else if (outcome === "cancelled") {
|
|
336978
|
+
log.withMetadata(fields).info("Subscribe cancelled");
|
|
336979
|
+
} else {
|
|
336980
|
+
log.withMetadata(fields).info("Subscribe ended");
|
|
336981
|
+
}
|
|
336982
|
+
};
|
|
336983
|
+
const writeTerminalError = async (frame, status14 = grpc13.status.UNKNOWN) => {
|
|
336984
|
+
terminalOutcome = "error";
|
|
336985
|
+
terminalGrpcStatus = grpcStatusName2(status14);
|
|
336986
|
+
await writeSubscribeError(call, isStreamClosed, frame);
|
|
336987
|
+
};
|
|
336988
|
+
log.withMetadata(operationalFields).info("Subscribe started");
|
|
336989
|
+
call.once("cancelled", () => {
|
|
336990
|
+
terminalGrpcStatus = "CANCELLED";
|
|
336991
|
+
markStreamClosed();
|
|
336992
|
+
logTerminalOutcome("cancelled");
|
|
336993
|
+
});
|
|
336864
336994
|
call.once("cancelled", closeOwnedBrokerOnCallEnd);
|
|
336865
336995
|
call.once("error", closeOwnedBrokerOnCallEnd);
|
|
336866
336996
|
call.once("end", () => {
|
|
336867
336997
|
markStreamClosed();
|
|
336868
|
-
|
|
336998
|
+
logTerminalOutcome(terminalOutcome);
|
|
336869
336999
|
const duration3 = Date.now() - subscribeStartTime;
|
|
336870
337000
|
otelMetrics?.recordHistogram("subscribe_duration_ms", duration3, {
|
|
336871
337001
|
cex: call.request?.cex || "unknown",
|
|
@@ -336874,12 +337004,16 @@ function createSubscribeHandler(deps) {
|
|
|
336874
337004
|
});
|
|
336875
337005
|
call.once("error", (error48) => {
|
|
336876
337006
|
markStreamClosed();
|
|
336877
|
-
|
|
337007
|
+
terminalOutcome = "error";
|
|
337008
|
+
terminalGrpcStatus = grpcStatusName2(typeof error48 === "object" && error48 !== null && "code" in error48 ? error48.code : undefined);
|
|
337009
|
+
logTerminalOutcome(call.cancelled ? "cancelled" : "error");
|
|
336878
337010
|
otelMetrics?.recordCounter("subscribe_errors_total", 1, {
|
|
336879
337011
|
error_type: error48 instanceof Error ? error48.message : "unknown"
|
|
336880
337012
|
});
|
|
336881
337013
|
});
|
|
336882
337014
|
if (!authenticateRequest(call, whitelistIps)) {
|
|
337015
|
+
terminalOutcome = "error";
|
|
337016
|
+
terminalGrpcStatus = "PERMISSION_DENIED";
|
|
336883
337017
|
otelMetrics?.recordCounter("subscribe_errors_total", 1, {
|
|
336884
337018
|
error_type: "permission_denied"
|
|
336885
337019
|
});
|
|
@@ -336890,32 +337024,22 @@ function createSubscribeHandler(deps) {
|
|
|
336890
337024
|
call.destroy(new Error("Access denied: Unauthorized IP"));
|
|
336891
337025
|
return;
|
|
336892
337026
|
}
|
|
336893
|
-
const metadata = call.metadata;
|
|
336894
|
-
let subscriptionType2 = SubscriptionType.ORDERBOOK;
|
|
336895
337027
|
try {
|
|
336896
|
-
const
|
|
336897
|
-
const { cex: cex3, symbol: symbol2, type: type2, options } = request;
|
|
336898
|
-
subscriptionType2 = resolveSubscriptionType(type2);
|
|
336899
|
-
log.info(`Request - Subscribe:`, {
|
|
336900
|
-
cex: request.cex,
|
|
336901
|
-
symbol: request.symbol,
|
|
336902
|
-
type: subscriptionType2
|
|
336903
|
-
});
|
|
336904
|
-
const subscriptionTypeName = getSubscriptionTypeName(subscriptionType2);
|
|
337028
|
+
const { options } = request;
|
|
336905
337029
|
otelMetrics?.recordCounter("subscribe_requests_total", 1, {
|
|
336906
337030
|
cex: cex3 || "unknown",
|
|
336907
337031
|
symbol: symbol2 || "unknown",
|
|
336908
337032
|
type: subscriptionTypeName
|
|
336909
337033
|
});
|
|
336910
337034
|
if (!cex3 || !symbol2) {
|
|
336911
|
-
await
|
|
337035
|
+
await writeTerminalError({
|
|
336912
337036
|
data: JSON.stringify({
|
|
336913
337037
|
error: "cex, symbol, and type are required"
|
|
336914
337038
|
}),
|
|
336915
337039
|
timestamp: Date.now(),
|
|
336916
337040
|
symbol: symbol2 || "",
|
|
336917
337041
|
type: subscriptionType2
|
|
336918
|
-
});
|
|
337042
|
+
}, grpc13.status.INVALID_ARGUMENT);
|
|
336919
337043
|
return;
|
|
336920
337044
|
}
|
|
336921
337045
|
if (isPublicMarketDataSubscription(subscriptionType2)) {
|
|
@@ -336944,7 +337068,7 @@ function createSubscribeHandler(deps) {
|
|
|
336944
337068
|
} catch (error48) {
|
|
336945
337069
|
const message = getErrorMessage(error48);
|
|
336946
337070
|
if (!isStreamClosed()) {
|
|
336947
|
-
await
|
|
337071
|
+
await writeTerminalError({
|
|
336948
337072
|
data: JSON.stringify({ error: message }),
|
|
336949
337073
|
timestamp: Date.now(),
|
|
336950
337074
|
symbol: symbol2,
|
|
@@ -336965,14 +337089,14 @@ function createSubscribeHandler(deps) {
|
|
|
336965
337089
|
const selectedBroker = selectedBrokerAccount?.exchange ?? createBroker(normalizedCex, metadata);
|
|
336966
337090
|
const broker = selectedBroker ?? createPublicBroker(normalizedCex);
|
|
336967
337091
|
if (!broker) {
|
|
336968
|
-
await
|
|
337092
|
+
await writeTerminalError({
|
|
336969
337093
|
data: JSON.stringify({
|
|
336970
337094
|
error: "Exchange not registered and no API metadata found"
|
|
336971
337095
|
}),
|
|
336972
337096
|
timestamp: Date.now(),
|
|
336973
337097
|
symbol: symbol2,
|
|
336974
337098
|
type: subscriptionType2
|
|
336975
|
-
});
|
|
337099
|
+
}, grpc13.status.NOT_FOUND);
|
|
336976
337100
|
return;
|
|
336977
337101
|
}
|
|
336978
337102
|
if (!selectedBrokerAccount) {
|
|
@@ -337000,28 +337124,28 @@ function createSubscribeHandler(deps) {
|
|
|
337000
337124
|
if (isBinanceSpotAccountSubscription(normalizedCex, subscriptionType2, options?.marketType)) {
|
|
337001
337125
|
const accountBroker = selectedBrokerAccount?.exchange ?? selectedBroker;
|
|
337002
337126
|
if (!accountBroker) {
|
|
337003
|
-
await
|
|
337127
|
+
await writeTerminalError({
|
|
337004
337128
|
data: JSON.stringify({
|
|
337005
337129
|
error: "Binance account subscriptions require API credentials"
|
|
337006
337130
|
}),
|
|
337007
337131
|
timestamp: Date.now(),
|
|
337008
337132
|
symbol: resolvedSymbol,
|
|
337009
337133
|
type: subscriptionType2
|
|
337010
|
-
});
|
|
337134
|
+
}, grpc13.status.FAILED_PRECONDITION);
|
|
337011
337135
|
return;
|
|
337012
337136
|
}
|
|
337013
337137
|
const marketId = subscriptionType2 === SubscriptionType.ORDERS ? await getBinanceMarketId(accountBroker, resolvedSymbol) : undefined;
|
|
337014
337138
|
let userDataSource;
|
|
337015
337139
|
if (selectedBrokerAccount) {
|
|
337016
337140
|
if (!userDataStreamSupervisor) {
|
|
337017
|
-
await
|
|
337141
|
+
await writeTerminalError({
|
|
337018
337142
|
data: JSON.stringify({
|
|
337019
337143
|
error: "Configured account user-data supervisor is unavailable"
|
|
337020
337144
|
}),
|
|
337021
337145
|
timestamp: Date.now(),
|
|
337022
337146
|
symbol: resolvedSymbol,
|
|
337023
337147
|
type: subscriptionType2
|
|
337024
|
-
});
|
|
337148
|
+
}, grpc13.status.FAILED_PRECONDITION);
|
|
337025
337149
|
return;
|
|
337026
337150
|
}
|
|
337027
337151
|
userDataSource = userDataStreamSupervisor.subscribe({
|
|
@@ -337044,7 +337168,7 @@ function createSubscribeHandler(deps) {
|
|
|
337044
337168
|
} catch (error48) {
|
|
337045
337169
|
const message = getErrorMessage(error48);
|
|
337046
337170
|
log.error(`Error fetching balance for ${cex3}:`, error48);
|
|
337047
|
-
await
|
|
337171
|
+
await writeTerminalError({
|
|
337048
337172
|
data: JSON.stringify({
|
|
337049
337173
|
error: `Failed to fetch balance: ${message}`
|
|
337050
337174
|
}),
|
|
@@ -337063,7 +337187,7 @@ function createSubscribeHandler(deps) {
|
|
|
337063
337187
|
} catch (error48) {
|
|
337064
337188
|
log.error(`Error fetching orders for ${resolvedSymbol} on ${cex3}:`, error48);
|
|
337065
337189
|
const message = getErrorMessage(error48);
|
|
337066
|
-
await
|
|
337190
|
+
await writeTerminalError({
|
|
337067
337191
|
data: JSON.stringify({
|
|
337068
337192
|
error: `Failed to fetch orders: ${message}`
|
|
337069
337193
|
}),
|
|
@@ -337074,26 +337198,27 @@ function createSubscribeHandler(deps) {
|
|
|
337074
337198
|
}
|
|
337075
337199
|
break;
|
|
337076
337200
|
default:
|
|
337077
|
-
await
|
|
337201
|
+
await writeTerminalError({
|
|
337078
337202
|
data: JSON.stringify({ error: "Invalid subscription type" }),
|
|
337079
337203
|
timestamp: Date.now(),
|
|
337080
337204
|
symbol: symbol2,
|
|
337081
337205
|
type: subscriptionType2
|
|
337082
|
-
});
|
|
337206
|
+
}, grpc13.status.INVALID_ARGUMENT);
|
|
337083
337207
|
}
|
|
337084
337208
|
} catch (error48) {
|
|
337085
337209
|
log.error("Error in Subscribe stream:", error48);
|
|
337086
337210
|
const message = getErrorMessage(error48);
|
|
337087
|
-
await
|
|
337211
|
+
await writeTerminalError({
|
|
337088
337212
|
data: JSON.stringify({ error: `Internal server error: ${message}` }),
|
|
337089
337213
|
timestamp: Date.now(),
|
|
337090
337214
|
symbol: "",
|
|
337091
337215
|
type: subscriptionType2
|
|
337092
|
-
});
|
|
337216
|
+
}, grpc13.status.INTERNAL);
|
|
337093
337217
|
} finally {
|
|
337094
337218
|
call.off("cancelled", closeOwnedBrokerOnCallEnd);
|
|
337095
337219
|
call.off("error", closeOwnedBrokerOnCallEnd);
|
|
337096
337220
|
await closeOwnedBroker();
|
|
337221
|
+
logTerminalOutcome(call.cancelled ? "cancelled" : terminalOutcome);
|
|
337097
337222
|
}
|
|
337098
337223
|
};
|
|
337099
337224
|
}
|
|
@@ -337587,12 +337712,7 @@ class CEXBroker {
|
|
|
337587
337712
|
if (this.brokerArchiver) {
|
|
337588
337713
|
await this.brokerArchiver.close();
|
|
337589
337714
|
}
|
|
337590
|
-
|
|
337591
|
-
await this.otelMetrics.close();
|
|
337592
|
-
}
|
|
337593
|
-
if (this.otelLogs) {
|
|
337594
|
-
await this.otelLogs.close();
|
|
337595
|
-
}
|
|
337715
|
+
await Promise.all([this.otelMetrics?.close(), this.otelLogs?.close()]);
|
|
337596
337716
|
}
|
|
337597
337717
|
async run() {
|
|
337598
337718
|
const marketArchiveState = resolveMarketCaptureArchiveState({
|
|
@@ -337717,7 +337837,24 @@ async function startBrokerCommand(policyPath, port, whitelistIps, verityProverUr
|
|
|
337717
337837
|
});
|
|
337718
337838
|
broker.loadEnvConfig();
|
|
337719
337839
|
await broker.run();
|
|
337840
|
+
return broker;
|
|
337841
|
+
}
|
|
337842
|
+
|
|
337843
|
+
// src/helpers/logger.ts
|
|
337844
|
+
var tslogLogger2 = new Logger({
|
|
337845
|
+
type: "pretty",
|
|
337846
|
+
stylePrettyLogs: true,
|
|
337847
|
+
minLevel: process.env.LOG_LEVEL === "debug" ? 0 : 3
|
|
337848
|
+
});
|
|
337849
|
+
var baseLogger2 = new LogLayer({
|
|
337850
|
+
transport: [new TsLogTransport({ id: "tslog", logger: tslogLogger2 })],
|
|
337851
|
+
plugins: [openTelemetryPlugin()],
|
|
337852
|
+
errorSerializer: serializeError
|
|
337853
|
+
});
|
|
337854
|
+
if (process.env.LOG_LEVEL !== "debug") {
|
|
337855
|
+
baseLogger2.setLevel("info");
|
|
337720
337856
|
}
|
|
337857
|
+
var log2 = baseLogger2;
|
|
337721
337858
|
|
|
337722
337859
|
// src/cli.ts
|
|
337723
337860
|
var program2 = new Command;
|
|
@@ -337728,15 +337865,35 @@ program2.name("cex-broker").description("CLI to start the CEXBroker service").re
|
|
|
337728
337865
|
const isValidIPv4 = (ip) => /^(\d{1,3}\.){3}\d{1,3}$/.test(ip) && ip.split(".").every((part) => Number(part) >= 0 && Number(part) <= 255);
|
|
337729
337866
|
for (const ip of whitelist) {
|
|
337730
337867
|
if (!isValidIPv4(ip)) {
|
|
337731
|
-
|
|
337732
|
-
process.exit(1);
|
|
337868
|
+
throw new Error(`Invalid IPv4 address: ${ip}`);
|
|
337733
337869
|
}
|
|
337734
337870
|
}
|
|
337735
337871
|
}
|
|
337736
|
-
await startBrokerCommand(options.policy, parseInt(options.port, 10), whitelist, options.verityProverUrl);
|
|
337872
|
+
const broker = await startBrokerCommand(options.policy, parseInt(options.port, 10), whitelist, options.verityProverUrl);
|
|
337873
|
+
let shutdownPromise;
|
|
337874
|
+
const onSignal = (signal) => {
|
|
337875
|
+
if (shutdownPromise)
|
|
337876
|
+
return;
|
|
337877
|
+
log2.withMetadata({ signal }).info("CEXBroker graceful shutdown requested");
|
|
337878
|
+
shutdownPromise = (async () => {
|
|
337879
|
+
try {
|
|
337880
|
+
await broker.stop();
|
|
337881
|
+
log2.withMetadata({ signal }).info("CEXBroker graceful shutdown complete");
|
|
337882
|
+
process.exitCode = 0;
|
|
337883
|
+
} catch (error48) {
|
|
337884
|
+
log2.withMetadata({ signal, error: error48 }).error("CEXBroker graceful shutdown failed");
|
|
337885
|
+
process.exitCode = 1;
|
|
337886
|
+
} finally {
|
|
337887
|
+
process.off("SIGTERM", onSignal);
|
|
337888
|
+
process.off("SIGINT", onSignal);
|
|
337889
|
+
}
|
|
337890
|
+
})();
|
|
337891
|
+
};
|
|
337892
|
+
process.on("SIGTERM", onSignal);
|
|
337893
|
+
process.on("SIGINT", onSignal);
|
|
337737
337894
|
} catch (err2) {
|
|
337738
337895
|
console.error("\u274C Failed to start broker:", err2);
|
|
337739
|
-
process.
|
|
337896
|
+
process.exitCode = 1;
|
|
337740
337897
|
}
|
|
337741
337898
|
});
|
|
337742
|
-
program2.
|
|
337899
|
+
await program2.parseAsync(process.argv);
|