@polyester/sdk 0.9.1 → 0.11.0
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/CHANGELOG.md +38 -0
- package/dist/catalogs/readers.d.ts.map +1 -1
- package/dist/catalogs/readers.js +22 -0
- package/dist/catalogs/readers.js.map +1 -1
- package/dist/core-client.d.ts.map +1 -1
- package/dist/core-client.js +49 -15
- package/dist/core-client.js.map +1 -1
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js +3 -2
- package/dist/environment.js.map +1 -1
- package/dist/gen/auth/v1/api_keys_pb.d.ts +8 -7
- package/dist/gen/auth/v1/api_keys_pb.d.ts.map +1 -1
- package/dist/gen/auth/v1/api_keys_pb.js.map +1 -1
- package/dist/gen/auth/v1/policies_pb.d.ts +8 -4
- package/dist/gen/auth/v1/policies_pb.d.ts.map +1 -1
- package/dist/gen/auth/v1/policies_pb.js.map +1 -1
- package/dist/gen/auth/v1/subaccounts_pb.d.ts +382 -18
- package/dist/gen/auth/v1/subaccounts_pb.d.ts.map +1 -1
- package/dist/gen/auth/v1/subaccounts_pb.js +253 -38
- package/dist/gen/auth/v1/subaccounts_pb.js.map +1 -1
- package/dist/gen/orders/v1/orders_pb.d.ts +2 -2
- package/dist/gen/orders/v1/orders_pb.js.map +1 -1
- package/dist/gen/orders/v1/orders_read_pb.d.ts +8 -0
- package/dist/gen/orders/v1/orders_read_pb.d.ts.map +1 -1
- package/dist/gen/orders/v1/orders_read_pb.js +1 -1
- package/dist/gen/orders/v1/orders_read_pb.js.map +1 -1
- package/dist/gen/ratelimit/v1/ratelimit_pb.d.ts +2 -2
- package/dist/gen/ratelimit/v1/ratelimit_pb.js +1 -1
- package/dist/gen/ratelimit/v1/ratelimit_pb.js.map +1 -1
- package/dist/gen/triggers/v1/triggers_pb.d.ts +4 -4
- package/dist/gen/triggers/v1/triggers_pb.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/realtime/client.d.ts.map +1 -1
- package/dist/realtime/client.js +13 -5
- package/dist/realtime/client.js.map +1 -1
- package/dist/realtime/ready-gated-subscription.js +68 -0
- package/dist/realtime/ready-gated-subscription.js.map +1 -0
- package/dist/realtime/snapshot-then-stream.js +19 -10
- package/dist/realtime/snapshot-then-stream.js.map +1 -1
- package/dist/server-client.d.ts +3 -1
- package/dist/server-client.d.ts.map +1 -1
- package/dist/server-client.js +9 -4
- package/dist/server-client.js.map +1 -1
- package/dist/services/auth/session.d.ts.map +1 -1
- package/dist/services/auth/session.js +4 -1
- package/dist/services/auth/session.js.map +1 -1
- package/dist/services/auth/token-storage.js +2 -2
- package/dist/services/auth/token-storage.js.map +1 -1
- package/dist/services/balances/balances.js +5 -8
- package/dist/services/balances/balances.js.map +1 -1
- package/dist/services/candles/candles.js +9 -12
- package/dist/services/candles/candles.js.map +1 -1
- package/dist/services/heatmap/heatmap.js +5 -8
- package/dist/services/heatmap/heatmap.js.map +1 -1
- package/dist/services/lifecycle/lifecycle.schemas.js +1 -1
- package/dist/services/market-data/market-data.d.ts.map +1 -1
- package/dist/services/market-data/market-data.js +5 -8
- package/dist/services/market-data/market-data.js.map +1 -1
- package/dist/services/market-data/market-data.schemas.d.ts.map +1 -1
- package/dist/services/market-data/market-data.schemas.js +3 -2
- package/dist/services/market-data/market-data.schemas.js.map +1 -1
- package/dist/services/market-overview/market-overview.d.ts.map +1 -1
- package/dist/services/market-overview/market-overview.js +7 -13
- package/dist/services/market-overview/market-overview.js.map +1 -1
- package/dist/services/orderbook/orderbook.d.ts.map +1 -1
- package/dist/services/orderbook/orderbook.js +18 -11
- package/dist/services/orderbook/orderbook.js.map +1 -1
- package/dist/services/orders/orders-batch.schemas.d.ts +6 -22
- package/dist/services/orders/orders-batch.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-batch.schemas.js +23 -20
- package/dist/services/orders/orders-batch.schemas.js.map +1 -1
- package/dist/services/orders/orders-identifiers.schemas.js +6 -1
- package/dist/services/orders/orders-identifiers.schemas.js.map +1 -1
- package/dist/services/orders/orders-input.schemas.d.ts +11 -43
- package/dist/services/orders/orders-input.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-input.schemas.js +10 -11
- package/dist/services/orders/orders-input.schemas.js.map +1 -1
- package/dist/services/orders/orders-modify.schemas.d.ts +1 -25
- package/dist/services/orders/orders-modify.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-modify.schemas.js +2 -4
- package/dist/services/orders/orders-modify.schemas.js.map +1 -1
- package/dist/services/orders/orders-output.schemas.d.ts +165 -27
- package/dist/services/orders/orders-output.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-output.schemas.js +1 -1
- package/dist/services/orders/orders-output.schemas.js.map +1 -1
- package/dist/services/orders/orders-risk.schemas.d.ts +1 -20
- package/dist/services/orders/orders-risk.schemas.d.ts.map +1 -1
- package/dist/services/orders/orders-risk.schemas.js +52 -15
- package/dist/services/orders/orders-risk.schemas.js.map +1 -1
- package/dist/services/orders/orders.codecs.js +12 -1
- package/dist/services/orders/orders.codecs.js.map +1 -1
- package/dist/services/orders/orders.d.ts.map +1 -1
- package/dist/services/orders/orders.js +6 -9
- package/dist/services/orders/orders.js.map +1 -1
- package/dist/services/rate-limits/rate-limits.schemas.d.ts +4 -4
- package/dist/services/rate-limits/rate-limits.schemas.js +1 -1
- package/dist/services/rate-limits/rate-limits.schemas.js.map +1 -1
- package/dist/services/subaccounts/index.d.ts +2 -2
- package/dist/services/subaccounts/subaccounts.codecs.js +29 -1
- package/dist/services/subaccounts/subaccounts.codecs.js.map +1 -1
- package/dist/services/subaccounts/subaccounts.d.ts +9 -1
- package/dist/services/subaccounts/subaccounts.d.ts.map +1 -1
- package/dist/services/subaccounts/subaccounts.js +19 -2
- package/dist/services/subaccounts/subaccounts.js.map +1 -1
- package/dist/services/subaccounts/subaccounts.schemas.d.ts +46 -6
- package/dist/services/subaccounts/subaccounts.schemas.d.ts.map +1 -1
- package/dist/services/subaccounts/subaccounts.schemas.js +28 -3
- package/dist/services/subaccounts/subaccounts.schemas.js.map +1 -1
- package/dist/services/subaccounts/subaccounts.types.d.ts +2 -2
- package/dist/services/trades/trades.d.ts +1 -1
- package/dist/services/trades/trades.js +6 -9
- package/dist/services/trades/trades.js.map +1 -1
- package/dist/services/trades/trades.schemas.d.ts +3 -0
- package/dist/services/trades/trades.schemas.d.ts.map +1 -1
- package/dist/services/trades/trades.schemas.js +2 -1
- package/dist/services/trades/trades.schemas.js.map +1 -1
- package/dist/services/trailing-oneof-inputs.js +3 -3
- package/dist/services/trailing-oneof-inputs.js.map +1 -1
- package/dist/services/transfers/index.d.ts +2 -2
- package/dist/services/transfers/transfers.d.ts +1 -2
- package/dist/services/transfers/transfers.d.ts.map +1 -1
- package/dist/services/transfers/transfers.js +8 -13
- package/dist/services/transfers/transfers.js.map +1 -1
- package/dist/services/transfers/transfers.schemas.d.ts +5 -5
- package/dist/services/transfers/transfers.schemas.d.ts.map +1 -1
- package/dist/services/transfers/transfers.schemas.js +31 -33
- package/dist/services/transfers/transfers.schemas.js.map +1 -1
- package/dist/services/triggers/trigger-input.schemas.d.ts +22 -9
- package/dist/services/triggers/trigger-input.schemas.d.ts.map +1 -1
- package/dist/services/triggers/trigger-input.schemas.js +20 -43
- package/dist/services/triggers/trigger-input.schemas.js.map +1 -1
- package/dist/services/triggers/triggers-output.schemas.d.ts +14 -14
- package/dist/services/triggers/triggers-output.schemas.js +5 -5
- package/dist/services/triggers/triggers-output.schemas.js.map +1 -1
- package/dist/services/triggers/triggers.d.ts.map +1 -1
- package/dist/services/triggers/triggers.js +10 -23
- package/dist/services/triggers/triggers.js.map +1 -1
- package/dist/services/zipper/zipper.d.ts.map +1 -1
- package/dist/services/zipper/zipper.js +15 -18
- package/dist/services/zipper/zipper.js.map +1 -1
- package/dist/shared/connect-error-mapping.d.ts.map +1 -1
- package/dist/shared/connect-error-mapping.js +9 -2
- package/dist/shared/connect-error-mapping.js.map +1 -1
- package/dist/shared/decimal-surface.d.ts.map +1 -1
- package/dist/shared/decimal-surface.js +40 -17
- package/dist/shared/decimal-surface.js.map +1 -1
- package/dist/shared/transports.d.ts.map +1 -1
- package/dist/shared/transports.js +33 -11
- package/dist/shared/transports.js.map +1 -1
- package/dist/utils/base58-id.js +1 -2
- package/dist/utils/base58-id.js.map +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +4 -3
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/event-emitter.d.ts.map +1 -1
- package/dist/utils/event-emitter.js +6 -3
- package/dist/utils/event-emitter.js.map +1 -1
- package/dist/utils/jwt.d.ts.map +1 -1
- package/dist/utils/jwt.js +2 -2
- package/dist/utils/jwt.js.map +1 -1
- package/dist/utils/numbers.js +20 -3
- package/dist/utils/numbers.js.map +1 -1
- package/dist/utils/timestamp.js +27 -16
- package/dist/utils/timestamp.js.map +1 -1
- package/dist/utils/u128.js +6 -18
- package/dist/utils/u128.js.map +1 -1
- package/dist/wired-services.d.ts.map +1 -1
- package/dist/wired-services.js +2 -1
- package/dist/wired-services.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,8 +3,7 @@ import { toConnectCallOptions } from "../../shared/request-options.js";
|
|
|
3
3
|
import { resolveAccountScopedInput } from "../subaccount-resolver.js";
|
|
4
4
|
import { accountScopeToSubaccountId } from "../../shared/account-scope.js";
|
|
5
5
|
import { AssetBalanceSchema, LedgerReadService } from "../../gen/ledger/read/v1/ledger_read_pb.js";
|
|
6
|
-
import {
|
|
7
|
-
import { createReadyGate } from "../../shared/decimal-surface.js";
|
|
6
|
+
import { connectReadyGatedProtoChannel } from "../../realtime/ready-gated-subscription.js";
|
|
8
7
|
import { BalanceHistoryInputSchema, BalancesListInputSchema, EquityHistoryInputSchema, createBalanceHistoryResponseSchema, createEquityHistoryResponseSchema, createLedgerBalanceSchema } from "./balances.schemas.js";
|
|
9
8
|
import { createClient } from "@connectrpc/connect";
|
|
10
9
|
import * as v from "valibot";
|
|
@@ -64,15 +63,13 @@ var BalancesService = class {
|
|
|
64
63
|
*/
|
|
65
64
|
subscribe(input) {
|
|
66
65
|
const channel = `private:ledger:balances:${input.accountId}:proto`;
|
|
67
|
-
|
|
68
|
-
return this.#realtime.connectProtoChannel({
|
|
66
|
+
return connectReadyGatedProtoChannel(this.#realtime, {
|
|
69
67
|
channel,
|
|
70
68
|
schema: AssetBalanceSchema,
|
|
69
|
+
ready: () => this.#scales.ready(),
|
|
71
70
|
onPublication: (data) => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
input.onEvent(b);
|
|
75
|
-
});
|
|
71
|
+
const b = parse(this.#ledgerBalanceSchema, data);
|
|
72
|
+
input.onEvent(b);
|
|
76
73
|
},
|
|
77
74
|
onConnected: input.onOpen,
|
|
78
75
|
onDisconnected: input.onClose,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balances.js","names":["#client","Proto.LedgerReadService","#realtime","#resolver","#scales","#ledgerBalanceSchema","#balanceHistoryResponseSchema","#equityHistoryResponseSchema","Proto.AssetBalanceSchema"],"sources":["../../../src/services/balances/balances.ts"],"sourcesContent":["import * as Proto from \"../../gen/ledger/read/v1/ledger_read_pb.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport
|
|
1
|
+
{"version":3,"file":"balances.js","names":["#client","Proto.LedgerReadService","#realtime","#resolver","#scales","#ledgerBalanceSchema","#balanceHistoryResponseSchema","#equityHistoryResponseSchema","Proto.AssetBalanceSchema"],"sources":["../../../src/services/balances/balances.ts"],"sourcesContent":["import * as Proto from \"../../gen/ledger/read/v1/ledger_read_pb.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport * as v from \"valibot\";\nimport { parse } from \"../../shared/validation.js\";\nimport type { PolyesterRealtime } from \"../../realtime/index.js\";\nimport { connectReadyGatedProtoChannel } from \"../../realtime/ready-gated-subscription.js\";\nimport { type SubaccountResolver, resolveAccountScopedInput } from \"../subaccount-resolver.js\";\nimport {\n toConnectCallOptions,\n type PolyesterRequestOptions,\n} from \"../../shared/request-options.js\";\nimport { accountScopeToSubaccountId, type AccountScopedInput } from \"../../shared/account-scope.js\";\nimport type { BaseSubscribeInput } from \"../../shared/types.js\";\nimport type { SdkScales } from \"../../shared/decimal-surface.js\";\nimport {\n BalanceHistoryInputSchema,\n BalancesListInputSchema,\n EquityHistoryInputSchema,\n createBalanceHistoryResponseSchema,\n createEquityHistoryResponseSchema,\n createLedgerBalanceSchema,\n type LedgerBalance,\n type BalanceHistoryInput,\n type BalanceHistoryResponse,\n type EquityHistoryInput,\n type EquityHistoryResponse,\n} from \"./balances.schemas.js\";\n\ninterface SubscribeBalancesInput extends BaseSubscribeInput<LedgerBalance> {\n accountId: string;\n}\n\n/**\n * Reads and streams ledger balances plus balance and equity history for the authenticated account scope.\n */\nexport class BalancesService {\n #client: Client<typeof Proto.LedgerReadService>;\n #realtime: PolyesterRealtime;\n #resolver?: SubaccountResolver;\n #scales: SdkScales;\n #ledgerBalanceSchema: ReturnType<typeof createLedgerBalanceSchema>;\n #balanceHistoryResponseSchema: ReturnType<typeof createBalanceHistoryResponseSchema>;\n #equityHistoryResponseSchema: ReturnType<typeof createEquityHistoryResponseSchema>;\n\n constructor(\n transport: Transport,\n realtime: PolyesterRealtime,\n resolver: SubaccountResolver | undefined,\n scales: SdkScales,\n ) {\n this.#client = createClient(Proto.LedgerReadService, transport);\n this.#realtime = realtime;\n this.#resolver = resolver;\n this.#scales = scales;\n this.#ledgerBalanceSchema = createLedgerBalanceSchema();\n this.#balanceHistoryResponseSchema = createBalanceHistoryResponseSchema();\n this.#equityHistoryResponseSchema = createEquityHistoryResponseSchema(scales);\n }\n\n /**\n * Returns current asset balances for the resolved root account or subaccount, including trading, funding, reserved, and available amounts as decimal strings.\n */\n async list(\n input: AccountScopedInput = {},\n options?: PolyesterRequestOptions,\n ): Promise<LedgerBalance[]> {\n await this.#scales.ready();\n const resolved = resolveAccountScopedInput(input, this.#resolver);\n const validated = parse(BalancesListInputSchema, resolved);\n const res = await this.#client.getBalances(\n {\n subaccountId: accountScopeToSubaccountId(validated.account),\n },\n toConnectCallOptions(options),\n );\n return parse(v.array(this.#ledgerBalanceSchema), res.balances);\n }\n\n /**\n * Returns columnar balance history for the resolved account scope over a selected range, optionally filtered by a non-negative integer ledger asset ID and account buckets. Ledger 0 or omission includes all assets.\n */\n async getBalanceHistory(\n input: BalanceHistoryInput,\n options?: PolyesterRequestOptions,\n ): Promise<BalanceHistoryResponse> {\n await this.#scales.ready();\n const resolved = resolveAccountScopedInput(input, this.#resolver);\n const validated = parse(BalanceHistoryInputSchema, resolved);\n const res = await this.#client.getBalanceHistory(validated, toConnectCallOptions(options));\n return parse(this.#balanceHistoryResponseSchema, res);\n }\n\n /**\n * Returns equity history series for the resolved account scope over a selected range, optionally grouped by account or asset and filtered by account buckets.\n */\n async getEquityHistory(\n input: EquityHistoryInput,\n options?: PolyesterRequestOptions,\n ): Promise<EquityHistoryResponse> {\n await this.#scales.ready();\n const resolved = resolveAccountScopedInput(input, this.#resolver);\n const validated = parse(EquityHistoryInputSchema, resolved);\n const res = await this.#client.getEquityHistorySeries(\n validated,\n toConnectCallOptions(options),\n );\n return parse(this.#equityHistoryResponseSchema, res);\n }\n\n /**\n * Subscribes to private balance updates on private:ledger:balances:{accountId}:proto and emits every balance record as a decimal-string row. Records for assets unknown to the catalog route a CatalogLookupError to onError.\n */\n subscribe(input: SubscribeBalancesInput): () => void {\n const channel = `private:ledger:balances:${input.accountId}:proto`;\n return connectReadyGatedProtoChannel(this.#realtime, {\n channel,\n schema: Proto.AssetBalanceSchema,\n ready: () => this.#scales.ready(),\n onPublication: (data) => {\n const b = parse(this.#ledgerBalanceSchema, data);\n input.onEvent(b);\n },\n onConnected: input.onOpen,\n onDisconnected: input.onClose,\n onError: input.onError,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAmCA,IAAa,kBAAb,MAA6B;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YACI,WACA,UACA,UACA,QACF;EACE,KAAKA,UAAU,aAAaC,mBAAyB,SAAS;EAC9D,KAAKC,YAAY;EACjB,KAAKC,YAAY;EACjB,KAAKC,UAAU;EACf,KAAKC,uBAAuB,0BAA0B;EACtD,KAAKC,gCAAgC,mCAAmC;EACxE,KAAKC,+BAA+B,kCAAkC,MAAM;CAChF;;;;CAKA,MAAM,KACF,QAA4B,CAAC,GAC7B,SACwB;EACxB,MAAM,KAAKH,QAAQ,MAAM;EACzB,MAAM,WAAW,0BAA0B,OAAO,KAAKD,SAAS;EAChE,MAAM,YAAY,MAAM,yBAAyB,QAAQ;EACzD,MAAM,MAAM,MAAM,KAAKH,QAAQ,YAC3B,EACI,cAAc,2BAA2B,UAAU,OAAO,EAC9D,GACA,qBAAqB,OAAO,CAChC;EACA,OAAO,MAAM,EAAE,MAAM,KAAKK,oBAAoB,GAAG,IAAI,QAAQ;CACjE;;;;CAKA,MAAM,kBACF,OACA,SAC+B;EAC/B,MAAM,KAAKD,QAAQ,MAAM;EACzB,MAAM,WAAW,0BAA0B,OAAO,KAAKD,SAAS;EAChE,MAAM,YAAY,MAAM,2BAA2B,QAAQ;EAC3D,MAAM,MAAM,MAAM,KAAKH,QAAQ,kBAAkB,WAAW,qBAAqB,OAAO,CAAC;EACzF,OAAO,MAAM,KAAKM,+BAA+B,GAAG;CACxD;;;;CAKA,MAAM,iBACF,OACA,SAC8B;EAC9B,MAAM,KAAKF,QAAQ,MAAM;EACzB,MAAM,WAAW,0BAA0B,OAAO,KAAKD,SAAS;EAChE,MAAM,YAAY,MAAM,0BAA0B,QAAQ;EAC1D,MAAM,MAAM,MAAM,KAAKH,QAAQ,uBAC3B,WACA,qBAAqB,OAAO,CAChC;EACA,OAAO,MAAM,KAAKO,8BAA8B,GAAG;CACvD;;;;CAKA,UAAU,OAA2C;EACjD,MAAM,UAAU,2BAA2B,MAAM,UAAU;EAC3D,OAAO,8BAA8B,KAAKL,WAAW;GACjD;GACA,QAAQM;GACR,aAAa,KAAKJ,QAAQ,MAAM;GAChC,gBAAgB,SAAS;IACrB,MAAM,IAAI,MAAM,KAAKC,sBAAsB,IAAI;IAC/C,MAAM,QAAQ,CAAC;GACnB;GACA,aAAa,MAAM;GACnB,gBAAgB,MAAM;GACtB,SAAS,MAAM;EACnB,CAAC;CACL;AACJ"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { parse } from "../../shared/validation.js";
|
|
2
2
|
import { toConnectCallOptions } from "../../shared/request-options.js";
|
|
3
|
-
import { publicationHandlerErrorContext } from "../../shared/subscription-errors.js";
|
|
4
3
|
import { CandlePointSchema, MarketDataService } from "../../gen/marketdata/v1/marketdata_pb.js";
|
|
5
|
-
import {
|
|
4
|
+
import { connectReadyGatedProtoChannel } from "../../realtime/ready-gated-subscription.js";
|
|
6
5
|
import { TimeframeCodec } from "./candles.codecs.js";
|
|
7
6
|
import { CandlePointSchema as CandlePointSchema$1, ListCandlesInputSchema, TimeframeSchema, createCandleColumnarIntSchema, createCandleColumnarSchema, createCandleRowIntSchema, createCandleRowSchema } from "./candles.schemas.js";
|
|
8
7
|
import { createClient } from "@connectrpc/connect";
|
|
@@ -82,20 +81,18 @@ var CandlesService = class {
|
|
|
82
81
|
});
|
|
83
82
|
const protoTimeframe = TimeframeCodec.inputToProto[params.timeframe];
|
|
84
83
|
const channel = `public:spot:market:candles:${params.timeframe}:${params.symbolId}:proto`;
|
|
85
|
-
|
|
86
|
-
return this.#realtime.connectProtoChannel({
|
|
84
|
+
return connectReadyGatedProtoChannel(this.#realtime, {
|
|
87
85
|
channel,
|
|
88
86
|
schema: CandlePointSchema,
|
|
87
|
+
ready: () => this.#scales.ready(),
|
|
89
88
|
onPublication: (data) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
timeframe: protoTimeframe
|
|
96
|
-
});
|
|
97
|
-
input.onEvent(candle);
|
|
89
|
+
const point = parse(CandlePointSchema$1, data);
|
|
90
|
+
const candle = parse(schema, {
|
|
91
|
+
...point,
|
|
92
|
+
symbolId: params.symbolId,
|
|
93
|
+
timeframe: protoTimeframe
|
|
98
94
|
});
|
|
95
|
+
input.onEvent(candle);
|
|
99
96
|
},
|
|
100
97
|
onConnected: input.onOpen,
|
|
101
98
|
onDisconnected: input.onClose,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"candles.js","names":["#client","Proto.MarketDataService","#realtime","#scales","#rowSchema","#rowIntSchema","#columnarSchema","#columnarIntSchema","CandlePointSchema","#subscribeWithSchema","Proto.CandlePointSchema"],"sources":["../../../src/services/candles/candles.ts"],"sourcesContent":["import { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport
|
|
1
|
+
{"version":3,"file":"candles.js","names":["#client","Proto.MarketDataService","#realtime","#scales","#rowSchema","#rowIntSchema","#columnarSchema","#columnarIntSchema","CandlePointSchema","#subscribeWithSchema","Proto.CandlePointSchema"],"sources":["../../../src/services/candles/candles.ts"],"sourcesContent":["import { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport * as Proto from \"../../gen/marketdata/v1/marketdata_pb.js\";\nimport * as v from \"valibot\";\nimport { parse } from \"../../shared/validation.js\";\nimport type { PolyesterRealtime } from \"../../realtime/types.js\";\nimport { connectReadyGatedProtoChannel } from \"../../realtime/ready-gated-subscription.js\";\nimport type { BaseSubscribeInput } from \"../../shared/types.js\";\nimport {\n toConnectCallOptions,\n type PolyesterRequestOptions,\n} from \"../../shared/request-options.js\";\nimport type { SdkScales } from \"../../shared/decimal-surface.js\";\nimport {\n type CandleColumnar,\n createCandleRowSchema,\n createCandleRowIntSchema,\n createCandleColumnarSchema,\n createCandleColumnarIntSchema,\n CandlePointSchema,\n TimeframeSchema,\n type Candle,\n type CandleInt,\n type Timeframe,\n type CandleColumnarInt,\n type GetCandlesInput,\n type GetCandlesColumnsInput,\n ListCandlesInputSchema,\n} from \"./candles.schemas.js\";\nimport { TimeframeCodec } from \"./candles.codecs.js\";\n\ninterface SubscribeCandlesInput extends BaseSubscribeInput<Candle> {\n symbolId: number;\n timeframe: Timeframe;\n}\n\ninterface SubscribeCandlesIntsInput extends BaseSubscribeInput<CandleInt> {\n symbolId: number;\n timeframe: Timeframe;\n}\n\nconst SubscribeCandlesParamsSchema = v.object({\n symbolId: v.pipe(v.number(), v.integer(), v.gtValue(0)),\n timeframe: TimeframeSchema,\n});\n\n/**\n * Reads and streams public spot OHLCV candle data in row and columnar formats.\n */\nexport class CandlesService {\n #client: Client<typeof Proto.MarketDataService>;\n #realtime: PolyesterRealtime;\n #scales: SdkScales;\n #rowSchema: ReturnType<typeof createCandleRowSchema>;\n #rowIntSchema: ReturnType<typeof createCandleRowIntSchema>;\n #columnarSchema: ReturnType<typeof createCandleColumnarSchema>;\n #columnarIntSchema: ReturnType<typeof createCandleColumnarIntSchema>;\n\n constructor(transport: Transport, realtime: PolyesterRealtime, scales: SdkScales) {\n this.#client = createClient(Proto.MarketDataService, transport);\n this.#realtime = realtime;\n this.#scales = scales;\n this.#rowSchema = createCandleRowSchema(scales);\n this.#rowIntSchema = createCandleRowIntSchema(scales);\n this.#columnarSchema = createCandleColumnarSchema(scales);\n this.#columnarIntSchema = createCandleColumnarIntSchema(scales);\n }\n\n /**\n * Returns OHLCV candles for a symbol/timeframe request, mapped into row objects with symbol id and timeframe. The proto response is newest-first and may include incomplete/reference data depending on input flags.\n */\n async list(input: GetCandlesInput, options?: PolyesterRequestOptions): Promise<Candle[]> {\n const validatedInput = parse(ListCandlesInputSchema, input);\n await this.#scales.ready();\n const res = await this.#client.getCandles(validatedInput, toConnectCallOptions(options));\n const candles = parse(v.optional(v.array(CandlePointSchema), []), res.candles);\n return candles.map((c) =>\n parse(this.#rowSchema, {\n ...c,\n symbolId: res.symbolId,\n timeframe: res.timeframe,\n }),\n );\n }\n\n /**\n * Returns candle data in chart-friendly column arrays ordered oldest-first by bucket start time. This preserves decimal-string SDK formatting from the columnar schema.\n */\n async listColumnar(\n input: GetCandlesColumnsInput,\n options?: PolyesterRequestOptions,\n ): Promise<CandleColumnar> {\n const validatedInput = parse(ListCandlesInputSchema, input);\n await this.#scales.ready();\n const res = await this.#client.getCandlesColumns(\n validatedInput,\n toConnectCallOptions(options),\n );\n return parse(this.#columnarSchema, res);\n }\n\n /**\n * Returns the same columnar candle series keyed by numeric bucket-start seconds (`tsSec`) instead of `time`.\n */\n async listColumnarInts(\n input: GetCandlesColumnsInput,\n options?: PolyesterRequestOptions,\n ): Promise<CandleColumnarInt> {\n const validatedInput = parse(ListCandlesInputSchema, input);\n await this.#scales.ready();\n const res = await this.#client.getCandlesColumns(\n validatedInput,\n toConnectCallOptions(options),\n );\n return parse(this.#columnarIntSchema, res);\n }\n\n /**\n * Subscribes to live candle updates on public:spot:market:candles:{timeframe}:{symbolId}:proto and emits row-form candles.\n */\n subscribe(input: SubscribeCandlesInput): () => void {\n return this.#subscribeWithSchema(input, this.#rowSchema);\n }\n\n /**\n * Subscribes to the same live candle channel as subscribe and emits row candles parsed through the row-int schema.\n */\n subscribeInts(input: SubscribeCandlesIntsInput): () => void {\n return this.#subscribeWithSchema(input, this.#rowIntSchema);\n }\n\n #subscribeWithSchema(\n input: SubscribeCandlesInput | SubscribeCandlesIntsInput,\n schema: ReturnType<typeof createCandleRowSchema>,\n ): () => void {\n const params = parse(SubscribeCandlesParamsSchema, {\n symbolId: input.symbolId,\n timeframe: input.timeframe,\n });\n const protoTimeframe = TimeframeCodec.inputToProto[params.timeframe];\n const channel = `public:spot:market:candles:${params.timeframe}:${params.symbolId}:proto`;\n return connectReadyGatedProtoChannel(this.#realtime, {\n channel,\n schema: Proto.CandlePointSchema,\n ready: () => this.#scales.ready(),\n onPublication: (data) => {\n const point = parse(CandlePointSchema, data);\n const candle = parse(schema, {\n ...point,\n symbolId: params.symbolId,\n timeframe: protoTimeframe,\n });\n input.onEvent(candle);\n },\n onConnected: input.onOpen,\n onDisconnected: input.onClose,\n onError: input.onError,\n });\n }\n}\n"],"mappings":";;;;;;;;;AAwCA,MAAM,+BAA+B,EAAE,OAAO;CAC1C,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,EAAE,QAAQ,GAAG,EAAE,QAAQ,CAAC,CAAC;CACtD,WAAW;AACf,CAAC;;;;AAKD,IAAa,iBAAb,MAA4B;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,WAAsB,UAA6B,QAAmB;EAC9E,KAAKA,UAAU,aAAaC,mBAAyB,SAAS;EAC9D,KAAKC,YAAY;EACjB,KAAKC,UAAU;EACf,KAAKC,aAAa,sBAAsB,MAAM;EAC9C,KAAKC,gBAAgB,yBAAyB,MAAM;EACpD,KAAKC,kBAAkB,2BAA2B,MAAM;EACxD,KAAKC,qBAAqB,8BAA8B,MAAM;CAClE;;;;CAKA,MAAM,KAAK,OAAwB,SAAsD;EACrF,MAAM,iBAAiB,MAAM,wBAAwB,KAAK;EAC1D,MAAM,KAAKJ,QAAQ,MAAM;EACzB,MAAM,MAAM,MAAM,KAAKH,QAAQ,WAAW,gBAAgB,qBAAqB,OAAO,CAAC;EAEvF,OADgB,MAAM,EAAE,SAAS,EAAE,MAAMQ,mBAAiB,GAAG,CAAC,CAAC,GAAG,IAAI,OACzD,CAAC,CAAC,KAAK,MAChB,MAAM,KAAKJ,YAAY;GACnB,GAAG;GACH,UAAU,IAAI;GACd,WAAW,IAAI;EACnB,CAAC,CACL;CACJ;;;;CAKA,MAAM,aACF,OACA,SACuB;EACvB,MAAM,iBAAiB,MAAM,wBAAwB,KAAK;EAC1D,MAAM,KAAKD,QAAQ,MAAM;EACzB,MAAM,MAAM,MAAM,KAAKH,QAAQ,kBAC3B,gBACA,qBAAqB,OAAO,CAChC;EACA,OAAO,MAAM,KAAKM,iBAAiB,GAAG;CAC1C;;;;CAKA,MAAM,iBACF,OACA,SAC0B;EAC1B,MAAM,iBAAiB,MAAM,wBAAwB,KAAK;EAC1D,MAAM,KAAKH,QAAQ,MAAM;EACzB,MAAM,MAAM,MAAM,KAAKH,QAAQ,kBAC3B,gBACA,qBAAqB,OAAO,CAChC;EACA,OAAO,MAAM,KAAKO,oBAAoB,GAAG;CAC7C;;;;CAKA,UAAU,OAA0C;EAChD,OAAO,KAAKE,qBAAqB,OAAO,KAAKL,UAAU;CAC3D;;;;CAKA,cAAc,OAA8C;EACxD,OAAO,KAAKK,qBAAqB,OAAO,KAAKJ,aAAa;CAC9D;CAEA,qBACI,OACA,QACU;EACV,MAAM,SAAS,MAAM,8BAA8B;GAC/C,UAAU,MAAM;GAChB,WAAW,MAAM;EACrB,CAAC;EACD,MAAM,iBAAiB,eAAe,aAAa,OAAO;EAC1D,MAAM,UAAU,8BAA8B,OAAO,UAAU,GAAG,OAAO,SAAS;EAClF,OAAO,8BAA8B,KAAKH,WAAW;GACjD;GACA,QAAQQ;GACR,aAAa,KAAKP,QAAQ,MAAM;GAChC,gBAAgB,SAAS;IACrB,MAAM,QAAQ,MAAMK,qBAAmB,IAAI;IAC3C,MAAM,SAAS,MAAM,QAAQ;KACzB,GAAG;KACH,UAAU,OAAO;KACjB,WAAW;IACf,CAAC;IACD,MAAM,QAAQ,MAAM;GACxB;GACA,aAAa,MAAM;GACnB,gBAAgB,MAAM;GACtB,SAAS,MAAM;EACnB,CAAC;CACL;AACJ"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { parse } from "../../shared/validation.js";
|
|
2
2
|
import { toConnectCallOptions } from "../../shared/request-options.js";
|
|
3
|
-
import {
|
|
4
|
-
import { createReadyGate } from "../../shared/decimal-surface.js";
|
|
3
|
+
import { connectReadyGatedProtoChannel } from "../../realtime/ready-gated-subscription.js";
|
|
5
4
|
import { HeatmapLiveBucketSchema, HeatmapService as HeatmapService$1, HeatmapTimeRangeSchema } from "../../gen/marketdata/v1/heatmap_pb.js";
|
|
6
5
|
import { HEATMAP_INTERVAL_VALUES } from "./heatmap.codecs.js";
|
|
7
6
|
import { GetOrderbookHeatmapInputSchema, createOrderbookHeatmapLiveBucketSchema, createOrderbookHeatmapResponseSchema } from "./heatmap.schemas.js";
|
|
@@ -58,15 +57,13 @@ var HeatmapService = class {
|
|
|
58
57
|
interval: input.interval
|
|
59
58
|
});
|
|
60
59
|
const channel = `public:spot:market:heatmap:${params.interval}:${params.symbolId}:proto`;
|
|
61
|
-
|
|
62
|
-
return this.#realtime.connectProtoChannel({
|
|
60
|
+
return connectReadyGatedProtoChannel(this.#realtime, {
|
|
63
61
|
channel,
|
|
64
62
|
schema: HeatmapLiveBucketSchema,
|
|
63
|
+
ready: () => this.#scales.ready(),
|
|
65
64
|
onPublication: (data) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
input.onEvent(bucket);
|
|
69
|
-
});
|
|
65
|
+
const bucket = parse(this.#liveBucketSchema, data);
|
|
66
|
+
input.onEvent(bucket);
|
|
70
67
|
},
|
|
71
68
|
onConnected: input.onOpen,
|
|
72
69
|
onDisconnected: input.onClose,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heatmap.js","names":["#client","HeatmapRpc","#realtime","#scales","#responseSchema","#liveBucketSchema","ProtoHeatmapLiveBucketSchema"],"sources":["../../../src/services/heatmap/heatmap.ts"],"sourcesContent":["import { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport { create } from \"@bufbuild/protobuf\";\nimport {
|
|
1
|
+
{"version":3,"file":"heatmap.js","names":["#client","HeatmapRpc","#realtime","#scales","#responseSchema","#liveBucketSchema","ProtoHeatmapLiveBucketSchema"],"sources":["../../../src/services/heatmap/heatmap.ts"],"sourcesContent":["import { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport { create } from \"@bufbuild/protobuf\";\nimport {\n HeatmapService as HeatmapRpc,\n HeatmapLiveBucketSchema as ProtoHeatmapLiveBucketSchema,\n HeatmapTimeRangeSchema,\n} from \"../../gen/marketdata/v1/heatmap_pb.js\";\nimport type { PolyesterRealtime } from \"../../realtime/types.js\";\nimport { connectReadyGatedProtoChannel } from \"../../realtime/ready-gated-subscription.js\";\nimport type { BaseSubscribeInput } from \"../../shared/types.js\";\nimport {\n toConnectCallOptions,\n type PolyesterRequestOptions,\n} from \"../../shared/request-options.js\";\nimport type { SdkScales } from \"../../shared/decimal-surface.js\";\nimport { HEATMAP_INTERVAL_VALUES, type HeatmapIntervalValue } from \"./heatmap.codecs.js\";\nimport * as v from \"valibot\";\nimport { parse } from \"../../shared/validation.js\";\nimport {\n GetOrderbookHeatmapInputSchema,\n createOrderbookHeatmapLiveBucketSchema,\n createOrderbookHeatmapResponseSchema,\n type GetOrderbookHeatmapInput,\n type OrderbookHeatmapLiveBucket,\n type OrderbookHeatmapResponse,\n} from \"./heatmap.schemas.js\";\n\nexport interface OrderbookHeatmapProvider {\n getOrderbookHeatmap(\n input: GetOrderbookHeatmapInput,\n options?: PolyesterRequestOptions,\n ): Promise<OrderbookHeatmapResponse>;\n}\n\ninterface SubscribeHeatmapLiveInput extends BaseSubscribeInput<OrderbookHeatmapLiveBucket> {\n symbolId: number;\n interval: HeatmapIntervalValue;\n}\n\nconst SubscribeHeatmapLiveParamsSchema = v.object({\n symbolId: v.pipe(v.number(), v.integer(), v.gtValue(0)),\n interval: v.picklist(HEATMAP_INTERVAL_VALUES),\n});\n\n/**\n * Reads historical order book heatmap chains and streams live heatmap buckets.\n */\nexport class HeatmapService implements OrderbookHeatmapProvider {\n #client: Client<typeof HeatmapRpc>;\n #realtime: PolyesterRealtime;\n #scales: SdkScales;\n #responseSchema: ReturnType<typeof createOrderbookHeatmapResponseSchema>;\n #liveBucketSchema: ReturnType<typeof createOrderbookHeatmapLiveBucketSchema>;\n\n constructor(transport: Transport, realtime: PolyesterRealtime, scales: SdkScales) {\n this.#client = createClient(HeatmapRpc, transport);\n this.#realtime = realtime;\n this.#scales = scales;\n this.#responseSchema = createOrderbookHeatmapResponseSchema(scales);\n this.#liveBucketSchema = createOrderbookHeatmapLiveBucketSchema(scales);\n }\n\n /**\n * Fetches order book heatmap data for a symbol, interval, depth, and quantity mode using either an absolute time range or cursor pagination. The response includes a keyframe anchor, delta buckets, pagination metadata, and live-anchor fields when available.\n */\n async getOrderbookHeatmap(\n input: GetOrderbookHeatmapInput,\n options?: PolyesterRequestOptions,\n ): Promise<OrderbookHeatmapResponse> {\n const parsed = parse(GetOrderbookHeatmapInputSchema, input);\n await this.#scales.ready();\n\n const res = await this.#client.getOrderbookHeatmap(\n {\n symbolId: parsed.symbolId,\n interval: parsed.interval,\n depth: parsed.depth,\n quantityMode: parsed.quantityMode,\n limit: parsed.limit,\n pageToken: parsed.pageToken,\n timeRange:\n parsed.timeRange != null\n ? create(HeatmapTimeRangeSchema, {\n startTime: parsed.timeRange.startTime,\n endTime: parsed.timeRange.endTime,\n })\n : undefined,\n },\n toConnectCallOptions(options),\n );\n return parse(this.#responseSchema, res);\n }\n\n /**\n * Subscribes to live heatmap buckets on public:spot:market:heatmap:{interval}:{symbolId}:proto and emits parsed bid/ask delta buckets for the selected interval.\n */\n subscribeLive(input: SubscribeHeatmapLiveInput): () => void {\n const params = parse(SubscribeHeatmapLiveParamsSchema, {\n symbolId: input.symbolId,\n interval: input.interval,\n });\n const channel = `public:spot:market:heatmap:${params.interval}:${params.symbolId}:proto`;\n return connectReadyGatedProtoChannel(this.#realtime, {\n channel,\n schema: ProtoHeatmapLiveBucketSchema,\n ready: () => this.#scales.ready(),\n onPublication: (data) => {\n const bucket = parse(this.#liveBucketSchema, data);\n input.onEvent(bucket);\n },\n onConnected: input.onOpen,\n onDisconnected: input.onClose,\n onError: input.onError,\n });\n }\n}\n"],"mappings":";;;;;;;;;;AAuCA,MAAM,mCAAmC,EAAE,OAAO;CAC9C,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,EAAE,QAAQ,GAAG,EAAE,QAAQ,CAAC,CAAC;CACtD,UAAU,EAAE,SAAS,uBAAuB;AAChD,CAAC;;;;AAKD,IAAa,iBAAb,MAAgE;CAC5D;CACA;CACA;CACA;CACA;CAEA,YAAY,WAAsB,UAA6B,QAAmB;EAC9E,KAAKA,UAAU,aAAaC,kBAAY,SAAS;EACjD,KAAKC,YAAY;EACjB,KAAKC,UAAU;EACf,KAAKC,kBAAkB,qCAAqC,MAAM;EAClE,KAAKC,oBAAoB,uCAAuC,MAAM;CAC1E;;;;CAKA,MAAM,oBACF,OACA,SACiC;EACjC,MAAM,SAAS,MAAM,gCAAgC,KAAK;EAC1D,MAAM,KAAKF,QAAQ,MAAM;EAEzB,MAAM,MAAM,MAAM,KAAKH,QAAQ,oBAC3B;GACI,UAAU,OAAO;GACjB,UAAU,OAAO;GACjB,OAAO,OAAO;GACd,cAAc,OAAO;GACrB,OAAO,OAAO;GACd,WAAW,OAAO;GAClB,WACI,OAAO,aAAa,OACd,OAAO,wBAAwB;IAC3B,WAAW,OAAO,UAAU;IAC5B,SAAS,OAAO,UAAU;GAC9B,CAAC,IACD,KAAA;EACd,GACA,qBAAqB,OAAO,CAChC;EACA,OAAO,MAAM,KAAKI,iBAAiB,GAAG;CAC1C;;;;CAKA,cAAc,OAA8C;EACxD,MAAM,SAAS,MAAM,kCAAkC;GACnD,UAAU,MAAM;GAChB,UAAU,MAAM;EACpB,CAAC;EACD,MAAM,UAAU,8BAA8B,OAAO,SAAS,GAAG,OAAO,SAAS;EACjF,OAAO,8BAA8B,KAAKF,WAAW;GACjD;GACA,QAAQI;GACR,aAAa,KAAKH,QAAQ,MAAM;GAChC,gBAAgB,SAAS;IACrB,MAAM,SAAS,MAAM,KAAKE,mBAAmB,IAAI;IACjD,MAAM,QAAQ,MAAM;GACxB;GACA,aAAa,MAAM;GACnB,gBAAgB,MAAM;GACtB,SAAS,MAAM;EACnB,CAAC;CACL;AACJ"}
|
|
@@ -2,10 +2,10 @@ import { requiredEnumLabel } from "../../shared/proto-enum-codec.js";
|
|
|
2
2
|
import { idToBigInt } from "../../utils/base58-id.js";
|
|
3
3
|
import { PublicIdSchema } from "../../shared/schemas.js";
|
|
4
4
|
import { scaledToDecimalOutput } from "../../shared/decimal-surface.js";
|
|
5
|
-
import { fromU128 } from "../../utils/u128.js";
|
|
6
5
|
import { FlowDomain, FlowKind, FlowState, LifecycleSource, RequestFeeStatus } from "../../gen/chain/lifecycle/v1/types_pb.js";
|
|
7
6
|
import { FlowStep, FlowStepActivityKind, FlowTimelineStatus } from "../../gen/chain/lifecycle/v1/lifecycle_read_pb.js";
|
|
8
7
|
import { LIFECYCLE_FLOW_KIND_VALUES, LIFECYCLE_FLOW_STATE_VALUES, LIFECYCLE_LIST_ORDER_BY_VALUES, LIFECYCLE_LIST_SCOPE_VALUES, LIFECYCLE_SORT_VALUES, LIFECYCLE_TX_LOOKUP_KIND_VALUES, LifecycleFlowDomainCodec, LifecycleFlowKindCodec, LifecycleFlowStateCodec, LifecycleFlowStepActivityKindCodec, LifecycleFlowStepCodec, LifecycleFlowTimelineStatusCodec, LifecycleListOrderByCodec, LifecycleListScopeCodec, LifecycleRequestFeeStatusCodec, LifecycleSortCodec, LifecycleSourceCodec, LifecycleTxLookupKindCodec, lifecycleReasonFromCode } from "./lifecycle.codecs.js";
|
|
8
|
+
import { fromU128 } from "../../utils/u128.js";
|
|
9
9
|
import * as v from "valibot";
|
|
10
10
|
//#region src/services/lifecycle/lifecycle.schemas.ts
|
|
11
11
|
const FlowKindSchema = v.picklist(LIFECYCLE_FLOW_KIND_VALUES);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market-data.d.ts","names":[],"sources":["../../../src/services/market-data/market-data.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"market-data.d.ts","names":[],"sources":["../../../src/services/market-data/market-data.ts"],"mappings":";;;;;;;;UAuBU,6BAA6B,mBAAmB;EACtD;;;;;cAMS;;EAMG,YAAA,WAAW,WAAW,UAAU,mBAAmB,QAAQ;;;;EAUjE,WACF,OAAO,sBACP,UAAU,0BACX;IAAU,QAAQ;IAAe;;;;;;;;;EAiB9B,cAAc,UAAU,0BAA0B,QAAQ;;;;EAQhE,gBAAgB,OAAO"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { parse } from "../../shared/validation.js";
|
|
2
2
|
import { toConnectCallOptions } from "../../shared/request-options.js";
|
|
3
|
-
import { publicationHandlerErrorContext } from "../../shared/subscription-errors.js";
|
|
4
3
|
import { MarketDataService as MarketDataService$1, MarketTradeSchema } from "../../gen/marketdata/v1/marketdata_pb.js";
|
|
5
|
-
import {
|
|
4
|
+
import { connectReadyGatedProtoChannel } from "../../realtime/ready-gated-subscription.js";
|
|
6
5
|
import { GetMarketTradesInputSchema, SpotConfigSchema, createMarketTradeSchema } from "./market-data.schemas.js";
|
|
7
6
|
import { isDev } from "../../utils/is-dev.js";
|
|
8
7
|
import { createClient } from "@connectrpc/connect";
|
|
@@ -54,15 +53,13 @@ var MarketDataService = class {
|
|
|
54
53
|
if (isDev()) console.error("Market trades subscription error", error);
|
|
55
54
|
input.onError?.(error);
|
|
56
55
|
};
|
|
57
|
-
|
|
58
|
-
return this.#realtime.connectProtoChannel({
|
|
56
|
+
return connectReadyGatedProtoChannel(this.#realtime, {
|
|
59
57
|
channel,
|
|
60
58
|
schema: MarketTradeSchema,
|
|
59
|
+
ready: () => this.#scales.ready(),
|
|
61
60
|
onPublication: (data) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
input.onEvent(trade);
|
|
65
|
-
});
|
|
61
|
+
const trade = parse(this.#marketTradeSchema, data);
|
|
62
|
+
input.onEvent(trade);
|
|
66
63
|
},
|
|
67
64
|
onConnected: () => input.onOpen?.(),
|
|
68
65
|
onDisconnected: () => input.onClose?.(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market-data.js","names":["#client","Proto.MarketDataService","#realtime","#scales","#marketTradeSchema","Proto.MarketTradeSchema"],"sources":["../../../src/services/market-data/market-data.ts"],"sourcesContent":["import * as Proto from \"../../gen/marketdata/v1/marketdata_pb.js\";\nimport type { PolyesterRealtime } from \"../../realtime/types.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport
|
|
1
|
+
{"version":3,"file":"market-data.js","names":["#client","Proto.MarketDataService","#realtime","#scales","#marketTradeSchema","Proto.MarketTradeSchema"],"sources":["../../../src/services/market-data/market-data.ts"],"sourcesContent":["import * as Proto from \"../../gen/marketdata/v1/marketdata_pb.js\";\nimport type { PolyesterRealtime } from \"../../realtime/types.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport type { SdkSubscriptionErrorContext } from \"../../shared/subscription-errors.js\";\nimport * as v from \"valibot\";\nimport { parse } from \"../../shared/validation.js\";\nimport type { BaseSubscribeInput } from \"../../shared/types.js\";\nimport { connectReadyGatedProtoChannel } from \"../../realtime/ready-gated-subscription.js\";\nimport {\n toConnectCallOptions,\n type PolyesterRequestOptions,\n} from \"../../shared/request-options.js\";\nimport type { SdkScales } from \"../../shared/decimal-surface.js\";\nimport {\n GetMarketTradesInputSchema,\n createMarketTradeSchema,\n type GetMarketTradesInput,\n type SpotConfig,\n SpotConfigSchema,\n type MarketTrade,\n} from \"./market-data.schemas.js\";\nimport { isDev } from \"../../utils/is-dev.js\";\n\ninterface SubscribeTradesInput extends BaseSubscribeInput<MarketTrade> {\n symbolId: number;\n}\n\n/**\n * Exposes public spot trades, spot configuration, and live trade streams.\n */\nexport class MarketDataService {\n #client: Client<typeof Proto.MarketDataService>;\n #realtime: PolyesterRealtime;\n #scales: SdkScales;\n #marketTradeSchema: ReturnType<typeof createMarketTradeSchema>;\n\n constructor(transport: Transport, realtime: PolyesterRealtime, scales: SdkScales) {\n this.#client = createClient(Proto.MarketDataService, transport);\n this.#realtime = realtime;\n this.#scales = scales;\n this.#marketTradeSchema = createMarketTradeSchema(scales);\n }\n\n /**\n * Returns recent public trades for one spot market, ordered newest-first by execution timestamp with match id as a tie-breaker. Supports limit, time bounds, side filtering, and match-id pagination.\n */\n async listTrades(\n input: GetMarketTradesInput,\n options?: PolyesterRequestOptions,\n ): Promise<{ trades: MarketTrade[]; nextPageToken: string }> {\n await this.#scales.ready();\n const validatedInput = parse(GetMarketTradesInputSchema, input);\n const res = await this.#client.getTrades(validatedInput, toConnectCallOptions(options));\n return {\n trades: parse(v.array(this.#marketTradeSchema), res.trades),\n nextPageToken: res.nextPageToken,\n };\n }\n\n /**\n * Returns the cacheable spot reference-data snapshot, including asset metadata, pair trading constraints, display scales, statuses, and market slippage defaults.\n *\n * This is the catalog's own data source, so it must never wait on catalog\n * readiness (that would deadlock the initial catalog refresh) and carries\n * no decimal conversion.\n */\n async getSpotConfig(options?: PolyesterRequestOptions): Promise<SpotConfig> {\n const res = await this.#client.getSpotConfig({}, toConnectCallOptions(options));\n return parse(SpotConfigSchema, res);\n }\n\n /**\n * Subscribes to public trade prints on public:spot:market:trades:{symbolId}:proto for the requested symbol and emits parsed market trades.\n */\n subscribeTrades(input: SubscribeTradesInput): () => void {\n const symbolId = parse(v.pipe(v.number(), v.integer(), v.gtValue(0)), input.symbolId);\n const channel = `public:spot:market:trades:${symbolId}:proto`;\n const notifyError = (error: SdkSubscriptionErrorContext) => {\n if (isDev()) {\n console.error(\"Market trades subscription error\", error);\n }\n input.onError?.(error);\n };\n return connectReadyGatedProtoChannel(this.#realtime, {\n channel,\n schema: Proto.MarketTradeSchema,\n ready: () => this.#scales.ready(),\n onPublication: (data) => {\n const trade = parse(this.#marketTradeSchema, data);\n input.onEvent(trade);\n },\n onConnected: () => input.onOpen?.(),\n onDisconnected: () => input.onClose?.(),\n onError: notifyError,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;AA8BA,IAAa,oBAAb,MAA+B;CAC3B;CACA;CACA;CACA;CAEA,YAAY,WAAsB,UAA6B,QAAmB;EAC9E,KAAKA,UAAU,aAAaC,qBAAyB,SAAS;EAC9D,KAAKC,YAAY;EACjB,KAAKC,UAAU;EACf,KAAKC,qBAAqB,wBAAwB,MAAM;CAC5D;;;;CAKA,MAAM,WACF,OACA,SACyD;EACzD,MAAM,KAAKD,QAAQ,MAAM;EACzB,MAAM,iBAAiB,MAAM,4BAA4B,KAAK;EAC9D,MAAM,MAAM,MAAM,KAAKH,QAAQ,UAAU,gBAAgB,qBAAqB,OAAO,CAAC;EACtF,OAAO;GACH,QAAQ,MAAM,EAAE,MAAM,KAAKI,kBAAkB,GAAG,IAAI,MAAM;GAC1D,eAAe,IAAI;EACvB;CACJ;;;;;;;;CASA,MAAM,cAAc,SAAwD;EACxE,MAAM,MAAM,MAAM,KAAKJ,QAAQ,cAAc,CAAC,GAAG,qBAAqB,OAAO,CAAC;EAC9E,OAAO,MAAM,kBAAkB,GAAG;CACtC;;;;CAKA,gBAAgB,OAAyC;EAErD,MAAM,UAAU,6BADC,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,EAAE,QAAQ,GAAG,EAAE,QAAQ,CAAC,CAAC,GAAG,MAAM,QACxB,EAAE;EACtD,MAAM,eAAe,UAAuC;GACxD,IAAI,MAAM,GACN,QAAQ,MAAM,oCAAoC,KAAK;GAE3D,MAAM,UAAU,KAAK;EACzB;EACA,OAAO,8BAA8B,KAAKE,WAAW;GACjD;GACA,QAAQG;GACR,aAAa,KAAKF,QAAQ,MAAM;GAChC,gBAAgB,SAAS;IACrB,MAAM,QAAQ,MAAM,KAAKC,oBAAoB,IAAI;IACjD,MAAM,QAAQ,KAAK;GACvB;GACA,mBAAmB,MAAM,SAAS;GAClC,sBAAsB,MAAM,UAAU;GACtC,SAAS;EACb,CAAC;CACL;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market-data.schemas.d.ts","names":[],"sources":["../../../src/services/market-data/market-data.schemas.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"market-data.schemas.d.ts","names":[],"sources":["../../../src/services/market-data/market-data.schemas.ts"],"mappings":";;;;;iBAmBgB,wBAAwB,QAAQ,YAAS,EAAA,yBAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;KA0B7C,cAAc,EAAE,YAAY,kBAAkB;iBAqB1C,oCAAgC,EAAA,yBAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;KAIpC,uBAAuB,EAAE,WACjC,kBAAkB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { tsNsToMs } from "../../utils/time.js";
|
|
2
|
+
import { optionalUint64DecimalFilterSchema } from "../../shared/schemas.js";
|
|
2
3
|
import { SideSchema } from "../shared.js";
|
|
3
4
|
import { timestampToMs, tsNsToTimestamp } from "../../utils/timestamp.js";
|
|
4
5
|
import "../../shared/catalog-config.js";
|
|
@@ -31,8 +32,8 @@ function createMarketTradeSchema(scales) {
|
|
|
31
32
|
const GetMarketTradesInputSchema = v.pipe(v.object({
|
|
32
33
|
symbolId: v.pipe(v.number(), v.integer(), v.gtValue(0)),
|
|
33
34
|
side: v.optional(SideSchema),
|
|
34
|
-
startTsNs:
|
|
35
|
-
endTsNs:
|
|
35
|
+
startTsNs: optionalUint64DecimalFilterSchema("startTsNs"),
|
|
36
|
+
endTsNs: optionalUint64DecimalFilterSchema("endTsNs"),
|
|
36
37
|
limit: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0), v.maxValue(1e3))),
|
|
37
38
|
pageToken: v.optional(v.pipe(v.string(), v.trim()), "")
|
|
38
39
|
}), v.transform((input) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market-data.schemas.js","names":[],"sources":["../../../src/services/market-data/market-data.schemas.ts"],"sourcesContent":["import * as v from \"valibot\";\nimport { SideSchema } from \"../shared.js\";\nimport {\n PAIR_STATUSES,\n type AssetConfig,\n type PairConfig,\n type PairMarketDataConfig,\n type PairStatus,\n type SpotConfig,\n} from \"../../shared/catalog-config.js\";\nimport { tsNsToMs } from \"../../utils/time.js\";\nimport { timestampToMs, tsNsToTimestamp } from \"../../utils/timestamp.js\";\nimport { scaledToDecimalOutput, type SdkScales } from \"../../shared/decimal-surface.js\";\nimport { PairStatusCodec, SideFilterCodec } from \"./market-data.codecs.js\";\n\nexport type { AssetConfig, PairConfig, PairMarketDataConfig, PairStatus, SpotConfig };\nexport { PAIR_STATUSES };\n\nexport function createMarketTradeSchema(scales: SdkScales) {\n return v.pipe(\n v.object({\n symbolId: v.number(),\n matchId: v.bigint(),\n isBuy: v.boolean(),\n priceTicks: v.bigint(),\n qtyScaled: v.bigint(),\n tsNs: v.optional(v.bigint(), 0n),\n }),\n v.transform((t) => {\n const sideLabel: v.InferOutput<typeof SideSchema> = t.isBuy ? \"buy\" : \"sell\";\n return {\n symbolId: t.symbolId,\n matchId: t.matchId.toString(),\n isBuy: t.isBuy,\n sideLabel,\n qty: scaledToDecimalOutput(t.qtyScaled, scales.baseQty(t.symbolId)),\n price: scaledToDecimalOutput(t.priceTicks, scales.price()),\n tsNs: t.tsNs.toString(),\n tsMs: tsNsToMs(t.tsNs),\n };\n }),\n );\n}\n\nexport type MarketTrade = v.InferOutput<ReturnType<typeof createMarketTradeSchema>>;\n\nexport const GetMarketTradesInputSchema = v.pipe(\n v.object({\n symbolId: v.pipe(v.number(), v.integer(), v.gtValue(0)),\n side: v.optional(SideSchema),\n startTsNs: v.pipe(\n v.optional(v.pipe(v.string(), v.trim())),\n v.transform((v) => (v ? BigInt(v) : undefined)),\n ),\n endTsNs: v.pipe(\n v.optional(v.pipe(v.string(), v.trim())),\n v.transform((v) => (v ? BigInt(v) : undefined)),\n ),\n limit: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0), v.maxValue(1_000))),\n pageToken: v.optional(v.pipe(v.string(), v.trim()), \"\"),\n }),\n v.transform((input) => ({\n symbolId: input.symbolId,\n side: input.side ? SideFilterCodec.inputToProto[input.side] : undefined,\n startTime: tsNsToTimestamp(input.startTsNs),\n endTime: tsNsToTimestamp(input.endTsNs),\n limit: input.limit,\n pageToken: input.pageToken,\n })),\n);\n\nexport function createGetMarketTradesInputSchema() {\n return GetMarketTradesInputSchema;\n}\n\nexport type GetMarketTradesInput = v.InferInput<\n ReturnType<typeof createGetMarketTradesInputSchema>\n>;\nexport type GetMarketTradesRequest = v.InferOutput<\n ReturnType<typeof createGetMarketTradesInputSchema>\n>;\n\nexport const AssetConfigSchema = v.pipe(\n v.object({\n /**\n * Asset identifier/symbol, e.g. 'USDT', 'BTC'.\n */\n asset: v.string(),\n /**\n * Internal ledger identifier for settlement systems.\n */\n ledgerId: v.number(),\n /**\n * The friendly display name for the asset (e.g. 'Bitcoin').\n */\n name: v.string(),\n /**\n * UI-only display precision for asset amounts/balances.\n */\n quantityDisplayDecimals: v.number(),\n /**\n * Fixed integer scaling for quantities/amounts in this asset (0..18).\n */\n quantityScale: v.number(),\n }),\n v.transform((a) => ({\n symbol: a.asset,\n ledgerId: a.ledgerId,\n name: a.name,\n quantityDisplayDecimals: a.quantityDisplayDecimals,\n quantityScale: a.quantityScale,\n })),\n);\n\nexport const PairMarketDataConfigSchema = v.optional(\n v.object({\n /**\n * Available price grouping sizes for the orderbook in quote units.\n * Allows viewing orders bucketed by larger increments (e.g., [0.01, 0.1, 1, 10]).\n */\n orderbookPriceBuckets: v.array(v.number()),\n }),\n {\n orderbookPriceBuckets: [] as number[],\n },\n);\n\nfunction bpsToPercent(bps: number): number {\n return bps / 100;\n}\n\nexport const PairConfigSchema = v.pipe(\n v.object({\n /**\n * Internal engine symbol id for the pair.\n */\n symbolId: v.number(),\n /**\n * Pair symbol string, e.g. 'BTC-USDT'\n */\n symbol: v.string(),\n /**\n * Base asset symbol, e.g. 'BTC'\n */\n baseAsset: v.string(),\n /**\n * Quote asset symbol, e.g. 'USDT'\n */\n quoteAsset: v.string(),\n /**\n * (e.g., \"0.01\") - The smallest price increment allowed. If tick size is 0.01, you can price at $100.00, $100.01, $100.02... but NOT $100.005.\n */\n tickSize: v.string(),\n /**\n * (e.g., \"0.0001\") - The smallest quantity increment allowed. If step size is 0.0001, you can order 100.0000, 100.0001, 100.0002... but NOT 100.00005.\n */\n stepSize: v.string(),\n /**\n * (e.g., \"1\") - Minimum order value in quote currency. If it's \"1\" and quote is USD, your order must be worth at least $1. So you can't buy $0.50 worth of something.\n */\n minNotionalQuote: v.string(),\n /**\n * Minimum quantity you can order in base currency terms. If it's \"0.001\" for BTC, smallest order is 0.001 BTC.\n */\n minQtyBase: v.string(),\n\n /**\n * Controls whether trading fee can be deducted from what you receive when buying.\n * Example\n * - You buy 1 ETH, fee is 0.1%\n * - if `true`, you receive 0.999 ETH (fee taken from ETH you're getting)\n * - if `false`, you receive 1 ETH, but you pay the fee separately in the quote currency (e.g., extra USDT)\n */\n allowBuyFeeFromBase: v.boolean(),\n /**\n * Default market slippage for buy orders in basis points from proto.\n */\n defaultMarketSlippageBpsBuy: v.optional(v.number(), 0),\n /**\n * Default market slippage for sell orders in basis points from proto.\n */\n defaultMarketSlippageBpsSell: v.optional(v.number(), 0),\n /**\n * Maximum server/client reference-price drift in basis points from proto.\n */\n maxClientRefDriftBps: v.optional(v.number(), 0),\n\n /**\n * Market-data configuration for this pair (orderbook bucket sizes, depths).\n */\n marketdata: v.optional(PairMarketDataConfigSchema),\n /**\n * Base asset quantity scale copied from AssetConfig.quantityScale.\n */\n baseQuantityScale: v.number(),\n /**\n * Quote asset quantity scale copied from AssetConfig.quantityScale.\n */\n quoteQuantityScale: v.number(),\n /**\n * Optional scheduled listing timestamp (UTC).\n */\n listingAt: v.pipe(v.optional(v.unknown()), v.transform(timestampToMs)),\n /**\n * Optional scheduled delisting timestamp (UTC).\n */\n delistingAt: v.pipe(v.optional(v.unknown()), v.transform(timestampToMs)),\n /**\n * Operational status of the pair.\n */\n status: v.pipe(\n v.number(),\n v.transform(\n (status): PairStatus =>\n PairStatusCodec.protoToOutput[\n status as keyof typeof PairStatusCodec.protoToOutput\n ] ?? \"unknown\",\n ),\n ),\n }),\n v.transform(\n ({\n defaultMarketSlippageBpsBuy,\n defaultMarketSlippageBpsSell,\n maxClientRefDriftBps,\n ...pair\n }) => ({\n ...pair,\n defaultMarketSlippagePctBuy: bpsToPercent(defaultMarketSlippageBpsBuy),\n defaultMarketSlippagePctSell: bpsToPercent(defaultMarketSlippageBpsSell),\n maxClientRefDriftPct: bpsToPercent(maxClientRefDriftBps),\n }),\n ),\n);\n\nexport const SpotConfigSchema = v.object({\n assets: v.array(AssetConfigSchema),\n pairs: v.array(PairConfigSchema),\n tsSec: v.pipe(\n v.bigint(),\n v.transform((v) => Number(v) * 1000),\n ),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"market-data.schemas.js","names":[],"sources":["../../../src/services/market-data/market-data.schemas.ts"],"sourcesContent":["import * as v from \"valibot\";\nimport { SideSchema } from \"../shared.js\";\nimport {\n PAIR_STATUSES,\n type AssetConfig,\n type PairConfig,\n type PairMarketDataConfig,\n type PairStatus,\n type SpotConfig,\n} from \"../../shared/catalog-config.js\";\nimport { tsNsToMs } from \"../../utils/time.js\";\nimport { timestampToMs, tsNsToTimestamp } from \"../../utils/timestamp.js\";\nimport { optionalUint64DecimalFilterSchema } from \"../../shared/schemas.js\";\nimport { scaledToDecimalOutput, type SdkScales } from \"../../shared/decimal-surface.js\";\nimport { PairStatusCodec, SideFilterCodec } from \"./market-data.codecs.js\";\n\nexport type { AssetConfig, PairConfig, PairMarketDataConfig, PairStatus, SpotConfig };\nexport { PAIR_STATUSES };\n\nexport function createMarketTradeSchema(scales: SdkScales) {\n return v.pipe(\n v.object({\n symbolId: v.number(),\n matchId: v.bigint(),\n isBuy: v.boolean(),\n priceTicks: v.bigint(),\n qtyScaled: v.bigint(),\n tsNs: v.optional(v.bigint(), 0n),\n }),\n v.transform((t) => {\n const sideLabel: v.InferOutput<typeof SideSchema> = t.isBuy ? \"buy\" : \"sell\";\n return {\n symbolId: t.symbolId,\n matchId: t.matchId.toString(),\n isBuy: t.isBuy,\n sideLabel,\n qty: scaledToDecimalOutput(t.qtyScaled, scales.baseQty(t.symbolId)),\n price: scaledToDecimalOutput(t.priceTicks, scales.price()),\n tsNs: t.tsNs.toString(),\n tsMs: tsNsToMs(t.tsNs),\n };\n }),\n );\n}\n\nexport type MarketTrade = v.InferOutput<ReturnType<typeof createMarketTradeSchema>>;\n\nexport const GetMarketTradesInputSchema = v.pipe(\n v.object({\n symbolId: v.pipe(v.number(), v.integer(), v.gtValue(0)),\n side: v.optional(SideSchema),\n startTsNs: optionalUint64DecimalFilterSchema(\"startTsNs\"),\n endTsNs: optionalUint64DecimalFilterSchema(\"endTsNs\"),\n limit: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0), v.maxValue(1_000))),\n pageToken: v.optional(v.pipe(v.string(), v.trim()), \"\"),\n }),\n v.transform((input) => ({\n symbolId: input.symbolId,\n side: input.side ? SideFilterCodec.inputToProto[input.side] : undefined,\n startTime: tsNsToTimestamp(input.startTsNs),\n endTime: tsNsToTimestamp(input.endTsNs),\n limit: input.limit,\n pageToken: input.pageToken,\n })),\n);\n\nexport function createGetMarketTradesInputSchema() {\n return GetMarketTradesInputSchema;\n}\n\nexport type GetMarketTradesInput = v.InferInput<\n ReturnType<typeof createGetMarketTradesInputSchema>\n>;\nexport type GetMarketTradesRequest = v.InferOutput<\n ReturnType<typeof createGetMarketTradesInputSchema>\n>;\n\nexport const AssetConfigSchema = v.pipe(\n v.object({\n /**\n * Asset identifier/symbol, e.g. 'USDT', 'BTC'.\n */\n asset: v.string(),\n /**\n * Internal ledger identifier for settlement systems.\n */\n ledgerId: v.number(),\n /**\n * The friendly display name for the asset (e.g. 'Bitcoin').\n */\n name: v.string(),\n /**\n * UI-only display precision for asset amounts/balances.\n */\n quantityDisplayDecimals: v.number(),\n /**\n * Fixed integer scaling for quantities/amounts in this asset (0..18).\n */\n quantityScale: v.number(),\n }),\n v.transform((a) => ({\n symbol: a.asset,\n ledgerId: a.ledgerId,\n name: a.name,\n quantityDisplayDecimals: a.quantityDisplayDecimals,\n quantityScale: a.quantityScale,\n })),\n);\n\nexport const PairMarketDataConfigSchema = v.optional(\n v.object({\n /**\n * Available price grouping sizes for the orderbook in quote units.\n * Allows viewing orders bucketed by larger increments (e.g., [0.01, 0.1, 1, 10]).\n */\n orderbookPriceBuckets: v.array(v.number()),\n }),\n {\n orderbookPriceBuckets: [] as number[],\n },\n);\n\nfunction bpsToPercent(bps: number): number {\n return bps / 100;\n}\n\nexport const PairConfigSchema = v.pipe(\n v.object({\n /**\n * Internal engine symbol id for the pair.\n */\n symbolId: v.number(),\n /**\n * Pair symbol string, e.g. 'BTC-USDT'\n */\n symbol: v.string(),\n /**\n * Base asset symbol, e.g. 'BTC'\n */\n baseAsset: v.string(),\n /**\n * Quote asset symbol, e.g. 'USDT'\n */\n quoteAsset: v.string(),\n /**\n * (e.g., \"0.01\") - The smallest price increment allowed. If tick size is 0.01, you can price at $100.00, $100.01, $100.02... but NOT $100.005.\n */\n tickSize: v.string(),\n /**\n * (e.g., \"0.0001\") - The smallest quantity increment allowed. If step size is 0.0001, you can order 100.0000, 100.0001, 100.0002... but NOT 100.00005.\n */\n stepSize: v.string(),\n /**\n * (e.g., \"1\") - Minimum order value in quote currency. If it's \"1\" and quote is USD, your order must be worth at least $1. So you can't buy $0.50 worth of something.\n */\n minNotionalQuote: v.string(),\n /**\n * Minimum quantity you can order in base currency terms. If it's \"0.001\" for BTC, smallest order is 0.001 BTC.\n */\n minQtyBase: v.string(),\n\n /**\n * Controls whether trading fee can be deducted from what you receive when buying.\n * Example\n * - You buy 1 ETH, fee is 0.1%\n * - if `true`, you receive 0.999 ETH (fee taken from ETH you're getting)\n * - if `false`, you receive 1 ETH, but you pay the fee separately in the quote currency (e.g., extra USDT)\n */\n allowBuyFeeFromBase: v.boolean(),\n /**\n * Default market slippage for buy orders in basis points from proto.\n */\n defaultMarketSlippageBpsBuy: v.optional(v.number(), 0),\n /**\n * Default market slippage for sell orders in basis points from proto.\n */\n defaultMarketSlippageBpsSell: v.optional(v.number(), 0),\n /**\n * Maximum server/client reference-price drift in basis points from proto.\n */\n maxClientRefDriftBps: v.optional(v.number(), 0),\n\n /**\n * Market-data configuration for this pair (orderbook bucket sizes, depths).\n */\n marketdata: v.optional(PairMarketDataConfigSchema),\n /**\n * Base asset quantity scale copied from AssetConfig.quantityScale.\n */\n baseQuantityScale: v.number(),\n /**\n * Quote asset quantity scale copied from AssetConfig.quantityScale.\n */\n quoteQuantityScale: v.number(),\n /**\n * Optional scheduled listing timestamp (UTC).\n */\n listingAt: v.pipe(v.optional(v.unknown()), v.transform(timestampToMs)),\n /**\n * Optional scheduled delisting timestamp (UTC).\n */\n delistingAt: v.pipe(v.optional(v.unknown()), v.transform(timestampToMs)),\n /**\n * Operational status of the pair.\n */\n status: v.pipe(\n v.number(),\n v.transform(\n (status): PairStatus =>\n PairStatusCodec.protoToOutput[\n status as keyof typeof PairStatusCodec.protoToOutput\n ] ?? \"unknown\",\n ),\n ),\n }),\n v.transform(\n ({\n defaultMarketSlippageBpsBuy,\n defaultMarketSlippageBpsSell,\n maxClientRefDriftBps,\n ...pair\n }) => ({\n ...pair,\n defaultMarketSlippagePctBuy: bpsToPercent(defaultMarketSlippageBpsBuy),\n defaultMarketSlippagePctSell: bpsToPercent(defaultMarketSlippageBpsSell),\n maxClientRefDriftPct: bpsToPercent(maxClientRefDriftBps),\n }),\n ),\n);\n\nexport const SpotConfigSchema = v.object({\n assets: v.array(AssetConfigSchema),\n pairs: v.array(PairConfigSchema),\n tsSec: v.pipe(\n v.bigint(),\n v.transform((v) => Number(v) * 1000),\n ),\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market-overview.d.ts","names":[],"sources":["../../../src/services/market-overview/market-overview.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"market-overview.d.ts","names":[],"sources":["../../../src/services/market-overview/market-overview.ts"],"mappings":";;;;;;;UAoBU,qCAAqC,mBAAmB;EAC9D;EACA,qBAAqB;;;;;cAMZ;;EAMG,YAAA,WAAW,WAAW,UAAU,mBAAmB,QAAQ;;;;EAUjE,KACF,QAAO,yBACP,UAAU,0BACX;IAAU,SAAS;IAAkB;;;;;EAgBxC,UAAU,OAAO"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { parse } from "../../shared/validation.js";
|
|
2
2
|
import { toConnectCallOptions } from "../../shared/request-options.js";
|
|
3
|
-
import { publicationHandlerErrorContext } from "../../shared/subscription-errors.js";
|
|
4
|
-
import { createReadyGate } from "../../shared/decimal-surface.js";
|
|
5
3
|
import { MarketOverviewBatchSchema, MarketOverviewService as MarketOverviewService$1 } from "../../gen/marketoverview/v1/marketoverview_pb.js";
|
|
6
4
|
import { snapshotThenStream } from "../../realtime/snapshot-then-stream.js";
|
|
7
5
|
import { ListMarketOverviewInputSchema, createMarketOverviewSchema } from "./market-overview.schemas.js";
|
|
@@ -44,7 +42,6 @@ var MarketOverviewService = class {
|
|
|
44
42
|
const sparklineIntervals = input.sparklineIntervals ?? ["24h"];
|
|
45
43
|
const listMarketOverview = this.list.bind(this);
|
|
46
44
|
const schema = this.#marketOverviewSchema;
|
|
47
|
-
const gate = createReadyGate(() => this.#scales.ready(), (error) => input.onError?.(publicationHandlerErrorContext(channel, error)));
|
|
48
45
|
function emit() {
|
|
49
46
|
input.onEvent(Array.from(bySymbolId.values()));
|
|
50
47
|
}
|
|
@@ -71,19 +68,16 @@ var MarketOverviewService = class {
|
|
|
71
68
|
snapshotErrorLog: "Failed to fetch market overview",
|
|
72
69
|
fetchSnapshot,
|
|
73
70
|
readPublication: (batch) => batch.markets ?? [],
|
|
71
|
+
bufferPublicationKey: (market) => market.symbolId,
|
|
74
72
|
applySnapshot: (markets, bufferedMarkets) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
emit();
|
|
80
|
-
});
|
|
73
|
+
bySymbolId.clear();
|
|
74
|
+
applyMarkets(markets);
|
|
75
|
+
applyMarkets(parseMarkets(bufferedMarkets));
|
|
76
|
+
emit();
|
|
81
77
|
},
|
|
82
78
|
applyLivePublications: (markets) => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
emit();
|
|
86
|
-
});
|
|
79
|
+
applyMarkets(parseMarkets(markets));
|
|
80
|
+
emit();
|
|
87
81
|
},
|
|
88
82
|
onOpen: input.onOpen,
|
|
89
83
|
onClose: input.onClose,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"market-overview.js","names":["#client","Proto.MarketOverviewService","#realtime","#scales","#marketOverviewSchema","Proto.MarketOverviewBatchSchema"],"sources":["../../../src/services/market-overview/market-overview.ts"],"sourcesContent":["import * as Proto from \"../../gen/marketoverview/v1/marketoverview_pb.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport
|
|
1
|
+
{"version":3,"file":"market-overview.js","names":["#client","Proto.MarketOverviewService","#realtime","#scales","#marketOverviewSchema","Proto.MarketOverviewBatchSchema"],"sources":["../../../src/services/market-overview/market-overview.ts"],"sourcesContent":["import * as Proto from \"../../gen/marketoverview/v1/marketoverview_pb.js\";\nimport { createClient, type Client, type Transport } from \"@connectrpc/connect\";\nimport * as v from \"valibot\";\nimport { parse } from \"../../shared/validation.js\";\nimport type { PolyesterRealtime } from \"../../realtime/types.js\";\nimport { snapshotThenStream } from \"../../realtime/snapshot-then-stream.js\";\nimport type { BaseSubscribeInput } from \"../../shared/types.js\";\nimport {\n toConnectCallOptions,\n type PolyesterRequestOptions,\n} from \"../../shared/request-options.js\";\nimport type { SdkScales } from \"../../shared/decimal-surface.js\";\nimport {\n ListMarketOverviewInputSchema,\n createMarketOverviewSchema,\n type SparklineIntervalName,\n type ListMarketOverviewInput,\n type MarketOverview,\n} from \"./market-overview.schemas.js\";\n\ninterface SubscribeMarketOverviewInput extends BaseSubscribeInput<MarketOverview[]> {\n includeSparklines?: boolean;\n sparklineIntervals?: SparklineIntervalName[];\n}\n\n/**\n * Provides ticker-style per-market stats and a live merged overview stream.\n */\nexport class MarketOverviewService {\n #client: Client<typeof Proto.MarketOverviewService>;\n #realtime: PolyesterRealtime;\n #scales: SdkScales;\n #marketOverviewSchema: ReturnType<typeof createMarketOverviewSchema>;\n\n constructor(transport: Transport, realtime: PolyesterRealtime, scales: SdkScales) {\n this.#client = createClient(Proto.MarketOverviewService, transport);\n this.#realtime = realtime;\n this.#scales = scales;\n this.#marketOverviewSchema = createMarketOverviewSchema(scales);\n }\n\n /**\n * Returns market overview rows with last and index prices, 24h stats, top-of-book values, listing timestamp, and optional sparklines. Supports symbol ID filtering, sorting, pagination, and sparkline interval selection.\n */\n async list(\n input: ListMarketOverviewInput = {},\n options?: PolyesterRequestOptions,\n ): Promise<{ markets: MarketOverview[]; nextPageToken: string }> {\n const validatedInput = parse(ListMarketOverviewInputSchema, input);\n await this.#scales.ready();\n const res = await this.#client.listMarketOverview(\n validatedInput,\n toConnectCallOptions(options),\n );\n return {\n markets: parse(v.array(this.#marketOverviewSchema), res.markets),\n nextPageToken: res.nextPageToken,\n };\n }\n\n /**\n * Subscribes to public:spot:market_overview:updates:proto, fetches an initial snapshot, buffers updates until ready, and emits the merged set of latest market rows. On reconnect it refetches the snapshot before resuming updates.\n */\n subscribe(input: SubscribeMarketOverviewInput): () => void {\n const channel = \"public:spot:market_overview:updates:proto\";\n const bySymbolId = new Map<number, MarketOverview>();\n const includeSparklines = input.includeSparklines ?? true;\n const sparklineIntervals = input.sparklineIntervals ?? [\"24h\"];\n const listMarketOverview = this.list.bind(this);\n const schema = this.#marketOverviewSchema;\n function emit(): void {\n input.onEvent(Array.from(bySymbolId.values()));\n }\n\n function handleMarketUpdate(m: MarketOverview): void {\n bySymbolId.set(m.symbolId, m);\n }\n\n function applyMarkets(markets: readonly MarketOverview[]): void {\n for (const market of markets) {\n handleMarketUpdate(market);\n }\n }\n\n function parseMarkets(markets: readonly Proto.MarketOverview[]): MarketOverview[] {\n return markets.map((m) => parse(schema, m));\n }\n\n async function fetchSnapshot(): Promise<MarketOverview[]> {\n const result = await listMarketOverview({\n includeSparklines,\n sparklineIntervals,\n });\n return result.markets;\n }\n\n const stream = snapshotThenStream({\n realtime: this.#realtime,\n channel,\n schema: Proto.MarketOverviewBatchSchema,\n maxBufferedPublications: 2000,\n snapshotErrorLog: \"Failed to fetch market overview\",\n fetchSnapshot,\n readPublication: (batch) => batch.markets ?? [],\n bufferPublicationKey: (market) => market.symbolId,\n applySnapshot: (markets, bufferedMarkets) => {\n bySymbolId.clear();\n applyMarkets(markets);\n applyMarkets(parseMarkets(bufferedMarkets));\n emit();\n },\n applyLivePublications: (markets) => {\n applyMarkets(parseMarkets(markets));\n emit();\n },\n onOpen: input.onOpen,\n onClose: input.onClose,\n onError: input.onError,\n });\n\n function dispose(): void {\n stream.unsubscribe();\n }\n\n return dispose;\n }\n}\n"],"mappings":";;;;;;;;;;;AA4BA,IAAa,wBAAb,MAAmC;CAC/B;CACA;CACA;CACA;CAEA,YAAY,WAAsB,UAA6B,QAAmB;EAC9E,KAAKA,UAAU,aAAaC,yBAA6B,SAAS;EAClE,KAAKC,YAAY;EACjB,KAAKC,UAAU;EACf,KAAKC,wBAAwB,2BAA2B,MAAM;CAClE;;;;CAKA,MAAM,KACF,QAAiC,CAAC,GAClC,SAC6D;EAC7D,MAAM,iBAAiB,MAAM,+BAA+B,KAAK;EACjE,MAAM,KAAKD,QAAQ,MAAM;EACzB,MAAM,MAAM,MAAM,KAAKH,QAAQ,mBAC3B,gBACA,qBAAqB,OAAO,CAChC;EACA,OAAO;GACH,SAAS,MAAM,EAAE,MAAM,KAAKI,qBAAqB,GAAG,IAAI,OAAO;GAC/D,eAAe,IAAI;EACvB;CACJ;;;;CAKA,UAAU,OAAiD;EACvD,MAAM,UAAU;EAChB,MAAM,6BAAa,IAAI,IAA4B;EACnD,MAAM,oBAAoB,MAAM,qBAAqB;EACrD,MAAM,qBAAqB,MAAM,sBAAsB,CAAC,KAAK;EAC7D,MAAM,qBAAqB,KAAK,KAAK,KAAK,IAAI;EAC9C,MAAM,SAAS,KAAKA;EACpB,SAAS,OAAa;GAClB,MAAM,QAAQ,MAAM,KAAK,WAAW,OAAO,CAAC,CAAC;EACjD;EAEA,SAAS,mBAAmB,GAAyB;GACjD,WAAW,IAAI,EAAE,UAAU,CAAC;EAChC;EAEA,SAAS,aAAa,SAA0C;GAC5D,KAAK,MAAM,UAAU,SACjB,mBAAmB,MAAM;EAEjC;EAEA,SAAS,aAAa,SAA4D;GAC9E,OAAO,QAAQ,KAAK,MAAM,MAAM,QAAQ,CAAC,CAAC;EAC9C;EAEA,eAAe,gBAA2C;GAKtD,QAAO,MAJc,mBAAmB;IACpC;IACA;GACJ,CAAC,EAAA,CACa;EAClB;EAEA,MAAM,SAAS,mBAAmB;GAC9B,UAAU,KAAKF;GACf;GACA,QAAQG;GACR,yBAAyB;GACzB,kBAAkB;GAClB;GACA,kBAAkB,UAAU,MAAM,WAAW,CAAC;GAC9C,uBAAuB,WAAW,OAAO;GACzC,gBAAgB,SAAS,oBAAoB;IACzC,WAAW,MAAM;IACjB,aAAa,OAAO;IACpB,aAAa,aAAa,eAAe,CAAC;IAC1C,KAAK;GACT;GACA,wBAAwB,YAAY;IAChC,aAAa,aAAa,OAAO,CAAC;IAClC,KAAK;GACT;GACA,QAAQ,MAAM;GACd,SAAS,MAAM;GACf,SAAS,MAAM;EACnB,CAAC;EAED,SAAS,UAAgB;GACrB,OAAO,YAAY;EACvB;EAEA,OAAO;CACX;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orderbook.d.ts","names":[],"sources":["../../../src/services/orderbook/orderbook.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"orderbook.d.ts","names":[],"sources":["../../../src/services/orderbook/orderbook.ts"],"mappings":";;;;;;;;UA2BU,gCAAgC,mBAAmB;EACzD;EACA;EACA;;UAGa,gCAAgC,mBAAmB;UAEnD;EACb;EACA,YAAY;;UAGC,yCAET,yBACA,KAAK;;;;cAOA;;EAKG,YAAA,WAAW,WAAW,UAAU,mBAAmB,QAAQ;;;;EASjE,IACF,OAAO,EAAE,kBAAkB,0BAC3B,UAAU,0BACX,QAAQ;;;;EAmBX,UAAU,OAAO;;;;;;;;EAWjB,mBAAmB,OAAO,mCAAmC"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { parse } from "../../shared/validation.js";
|
|
2
2
|
import { toConnectCallOptions } from "../../shared/request-options.js";
|
|
3
|
+
import { decimalInputToScaled } from "../../shared/decimal-surface.js";
|
|
3
4
|
import { publicationHandlerErrorContext } from "../../shared/subscription-errors.js";
|
|
4
|
-
import { createReadyGate, decimalInputToScaled } from "../../shared/decimal-surface.js";
|
|
5
5
|
import { isResourceNotFoundError } from "../../utils/errors.js";
|
|
6
6
|
import { snapshotThenStream } from "../../realtime/snapshot-then-stream.js";
|
|
7
7
|
import { GetOrderBookResponseSchema, OrderBookDeltaSchema, OrderbookService as OrderbookService$1 } from "../../gen/orderbook/v1/orderbook_pb.js";
|
|
8
8
|
import { orderbookWsChannelDepth } from "./orderbook.codecs.js";
|
|
9
9
|
import { GetOrderbookInputSchema, createOrderbookDataSchema, formatOrderbookLevel } from "./orderbook.schemas.js";
|
|
10
|
-
import { toBig } from "../../utils/u128.js";
|
|
11
10
|
import { create } from "@bufbuild/protobuf";
|
|
12
11
|
import { createClient } from "@connectrpc/connect";
|
|
13
12
|
//#region src/services/orderbook/orderbook.ts
|
|
@@ -64,7 +63,6 @@ var OrderbookService = class {
|
|
|
64
63
|
const channel = `public:spot:orderbook:deltas:depth:${channelDepth}:${symbolId}:proto`;
|
|
65
64
|
const client = this.#client;
|
|
66
65
|
const scales = this.#scales;
|
|
67
|
-
const gate = createReadyGate(() => scales.ready(), (error) => input.onError?.(publicationHandlerErrorContext(channel, error)));
|
|
68
66
|
let bidsMap = /* @__PURE__ */ new Map();
|
|
69
67
|
let asksMap = /* @__PURE__ */ new Map();
|
|
70
68
|
let currentBookSeq = 0n;
|
|
@@ -98,13 +96,14 @@ var OrderbookService = class {
|
|
|
98
96
|
const agg = /* @__PURE__ */ new Map();
|
|
99
97
|
for (const [priceTicks, qtyScaled] of map.entries()) {
|
|
100
98
|
if (qtyScaled <= 0n) continue;
|
|
101
|
-
const
|
|
99
|
+
const bucketFloor = priceTicks / bucket * bucket;
|
|
100
|
+
const bucketPrice = side === "asks" && bucketFloor !== priceTicks ? bucketFloor + bucket : bucketFloor;
|
|
102
101
|
agg.set(bucketPrice, (agg.get(bucketPrice) ?? 0n) + qtyScaled);
|
|
103
102
|
}
|
|
104
103
|
return sideToUI(agg, side, limit);
|
|
105
104
|
}
|
|
106
105
|
function emit() {
|
|
107
|
-
|
|
106
|
+
try {
|
|
108
107
|
input.onEvent({
|
|
109
108
|
symbolId,
|
|
110
109
|
depth: requestedDepth,
|
|
@@ -112,7 +111,9 @@ var OrderbookService = class {
|
|
|
112
111
|
bids: sideToUIBucketed(bidsMap, "bids", requestedDepth, bucketTicks),
|
|
113
112
|
asks: sideToUIBucketed(asksMap, "asks", requestedDepth, bucketTicks)
|
|
114
113
|
});
|
|
115
|
-
})
|
|
114
|
+
} catch (error) {
|
|
115
|
+
input.onError?.(publicationHandlerErrorContext(channel, error));
|
|
116
|
+
}
|
|
116
117
|
}
|
|
117
118
|
function setBucket(bucket) {
|
|
118
119
|
if (!bucket) bucketTicks = null;
|
|
@@ -124,6 +125,7 @@ var OrderbookService = class {
|
|
|
124
125
|
if (stream?.isReady()) emit();
|
|
125
126
|
}
|
|
126
127
|
async function inputServiceFetch() {
|
|
128
|
+
await scales.ready();
|
|
127
129
|
const validated = parse(GetOrderbookInputSchema, {
|
|
128
130
|
symbolId,
|
|
129
131
|
depth: channelDepth
|
|
@@ -144,6 +146,7 @@ var OrderbookService = class {
|
|
|
144
146
|
}
|
|
145
147
|
}
|
|
146
148
|
function handleDelta(delta) {
|
|
149
|
+
if (delta.bookSeqEnd <= currentBookSeq) return true;
|
|
147
150
|
if (delta.reset) {
|
|
148
151
|
bidsMap.clear();
|
|
149
152
|
asksMap.clear();
|
|
@@ -151,13 +154,13 @@ var OrderbookService = class {
|
|
|
151
154
|
}
|
|
152
155
|
if (currentBookSeq !== 0n && delta.bookSeqStart > currentBookSeq + 1n) {
|
|
153
156
|
stream?.refreshSnapshot();
|
|
154
|
-
return;
|
|
157
|
+
return false;
|
|
155
158
|
}
|
|
156
|
-
if (delta.bookSeqEnd <= currentBookSeq) return;
|
|
157
159
|
applySideDelta(bidsMap, delta.bids);
|
|
158
160
|
applySideDelta(asksMap, delta.asks);
|
|
159
161
|
currentBookSeq = delta.bookSeqEnd > currentBookSeq ? delta.bookSeqEnd : currentBookSeq;
|
|
160
162
|
emit();
|
|
163
|
+
return true;
|
|
161
164
|
}
|
|
162
165
|
setBucket(input.bucket);
|
|
163
166
|
stream = snapshotThenStream({
|
|
@@ -166,22 +169,26 @@ var OrderbookService = class {
|
|
|
166
169
|
schema: OrderBookDeltaSchema,
|
|
167
170
|
maxBufferedPublications: 200,
|
|
168
171
|
snapshotErrorLog: "Failed to fetch orderbook",
|
|
172
|
+
snapshotRetry: {
|
|
173
|
+
maxAttempts: 3,
|
|
174
|
+
delayMs: 1e3
|
|
175
|
+
},
|
|
169
176
|
fetchSnapshot: inputServiceFetch,
|
|
170
177
|
readPublication: (delta) => [delta],
|
|
171
178
|
applySnapshot: (snapshot, bufferedDeltas) => {
|
|
172
179
|
bidsMap = levelsToMap(snapshot.bids);
|
|
173
180
|
asksMap = levelsToMap(snapshot.asks);
|
|
174
|
-
currentBookSeq =
|
|
181
|
+
currentBookSeq = snapshot.bookSeq;
|
|
175
182
|
emit();
|
|
176
183
|
for (const delta of bufferedDeltas) {
|
|
177
184
|
if (stream?.isDisposed()) return;
|
|
178
|
-
handleDelta(delta);
|
|
185
|
+
if (!handleDelta(delta)) return;
|
|
179
186
|
}
|
|
180
187
|
},
|
|
181
188
|
applyLivePublications: (deltas) => {
|
|
182
189
|
for (const delta of deltas) {
|
|
183
190
|
if (stream?.isDisposed()) return;
|
|
184
|
-
handleDelta(delta);
|
|
191
|
+
if (!handleDelta(delta)) return;
|
|
185
192
|
}
|
|
186
193
|
},
|
|
187
194
|
onOpen: input.onOpen,
|