@k256/sdk 0.3.2 → 0.5.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/dist/index.cjs +112 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +112 -3
- package/dist/index.js.map +1 -1
- package/dist/leader-ws/index.cjs +11 -2
- package/dist/leader-ws/index.cjs.map +1 -1
- package/dist/leader-ws/index.d.cts +11 -3
- package/dist/leader-ws/index.d.ts +11 -3
- package/dist/leader-ws/index.js +11 -2
- package/dist/leader-ws/index.js.map +1 -1
- package/dist/ws/index.cjs +101 -0
- package/dist/ws/index.cjs.map +1 -1
- package/dist/ws/index.d.cts +76 -2
- package/dist/ws/index.d.ts +76 -2
- package/dist/ws/index.js +101 -1
- package/dist/ws/index.js.map +1 -1
- package/package.json +1 -1
- package/src/leader-ws/decoder.ts +13 -2
- package/src/leader-ws/types.ts +11 -3
- package/src/ws/client.ts +78 -3
- package/src/ws/decoder.ts +56 -1
- package/src/ws/index.ts +6 -1
- package/src/ws/types.ts +49 -0
package/dist/index.cjs
CHANGED
|
@@ -111,6 +111,16 @@ var MessageType = {
|
|
|
111
111
|
PoolUpdateBatch: 14,
|
|
112
112
|
/** Block-level statistics (v3) */
|
|
113
113
|
BlockStats: 15,
|
|
114
|
+
/** Subscribe to price updates (JSON) - Client → Server */
|
|
115
|
+
SubscribePrice: 16,
|
|
116
|
+
/** Single price update (bincode 56B) - Server → Client */
|
|
117
|
+
PriceUpdate: 17,
|
|
118
|
+
/** Batched price updates (bincode [u16 count][entries...]) - Server → Client */
|
|
119
|
+
PriceBatch: 18,
|
|
120
|
+
/** Initial price snapshot (same binary format as PriceBatch) - Server → Client */
|
|
121
|
+
PriceSnapshot: 19,
|
|
122
|
+
/** Unsubscribe from prices (no payload) - Client → Server */
|
|
123
|
+
UnsubscribePrice: 20,
|
|
114
124
|
/** Error message (UTF-8 string) */
|
|
115
125
|
Error: 255
|
|
116
126
|
};
|
|
@@ -309,10 +319,48 @@ function decodeMessage(data) {
|
|
|
309
319
|
receivedAt: Date.now()
|
|
310
320
|
};
|
|
311
321
|
}
|
|
322
|
+
case MessageType.PriceUpdate: {
|
|
323
|
+
if (payload.byteLength < 56) return null;
|
|
324
|
+
const mintBytes = new Uint8Array(payload, 0, 32);
|
|
325
|
+
return {
|
|
326
|
+
type: "price_update",
|
|
327
|
+
data: {
|
|
328
|
+
mint: base58Encode(mintBytes),
|
|
329
|
+
usdPrice: Number(payloadView.getBigUint64(32, true)) / 1e12,
|
|
330
|
+
slot: Number(payloadView.getBigUint64(40, true)),
|
|
331
|
+
timestampMs: Number(payloadView.getBigUint64(48, true))
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
case MessageType.PriceBatch:
|
|
336
|
+
case MessageType.PriceSnapshot: {
|
|
337
|
+
if (payload.byteLength < 2) return null;
|
|
338
|
+
const entries = decodePriceEntries(payload);
|
|
339
|
+
const priceType = msgType === MessageType.PriceSnapshot ? "price_snapshot" : "price_batch";
|
|
340
|
+
return { type: priceType, data: entries };
|
|
341
|
+
}
|
|
312
342
|
default:
|
|
313
343
|
return null;
|
|
314
344
|
}
|
|
315
345
|
}
|
|
346
|
+
function decodePriceEntries(payload) {
|
|
347
|
+
const view = new DataView(payload);
|
|
348
|
+
if (payload.byteLength < 2) return [];
|
|
349
|
+
const count = view.getUint16(0, true);
|
|
350
|
+
const entries = [];
|
|
351
|
+
let offset = 2;
|
|
352
|
+
for (let i = 0; i < count && offset + 56 <= payload.byteLength; i++) {
|
|
353
|
+
const mintBytes = new Uint8Array(payload, offset, 32);
|
|
354
|
+
entries.push({
|
|
355
|
+
mint: base58Encode(mintBytes),
|
|
356
|
+
usdPrice: Number(view.getBigUint64(offset + 32, true)) / 1e12,
|
|
357
|
+
slot: Number(view.getBigUint64(offset + 40, true)),
|
|
358
|
+
timestampMs: Number(view.getBigUint64(offset + 48, true))
|
|
359
|
+
});
|
|
360
|
+
offset += 56;
|
|
361
|
+
}
|
|
362
|
+
return entries;
|
|
363
|
+
}
|
|
316
364
|
function decodePoolUpdateBatch(payload) {
|
|
317
365
|
const view = new DataView(payload);
|
|
318
366
|
if (payload.byteLength < 2) return [];
|
|
@@ -535,6 +583,7 @@ var K256WebSocketClient = class {
|
|
|
535
583
|
lastHeartbeatTime = 0;
|
|
536
584
|
pendingSubscription = null;
|
|
537
585
|
pendingQuoteSubscription = null;
|
|
586
|
+
pendingPriceSubscription = null;
|
|
538
587
|
isIntentionallyClosed = false;
|
|
539
588
|
/** Current connection state */
|
|
540
589
|
get state() {
|
|
@@ -624,12 +673,33 @@ var K256WebSocketClient = class {
|
|
|
624
673
|
const msg = JSON.stringify({ type: "unsubscribe_quote", topicId });
|
|
625
674
|
this.ws?.send(msg);
|
|
626
675
|
}
|
|
676
|
+
/**
|
|
677
|
+
* Subscribe to real-time price updates
|
|
678
|
+
* @param options - Token mints and threshold configuration
|
|
679
|
+
*/
|
|
680
|
+
subscribePrices(options) {
|
|
681
|
+
this.pendingPriceSubscription = options;
|
|
682
|
+
if (!this.isConnected) {
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
this.sendPriceSubscription(options);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Unsubscribe from price updates
|
|
689
|
+
*/
|
|
690
|
+
unsubscribePrices() {
|
|
691
|
+
this.pendingPriceSubscription = null;
|
|
692
|
+
if (!this.isConnected) return;
|
|
693
|
+
const buf = new Uint8Array([MessageType.UnsubscribePrice]);
|
|
694
|
+
this.ws?.send(buf);
|
|
695
|
+
}
|
|
627
696
|
/**
|
|
628
697
|
* Unsubscribe from all channels
|
|
629
698
|
*/
|
|
630
699
|
unsubscribe() {
|
|
631
700
|
this.pendingSubscription = null;
|
|
632
701
|
this.pendingQuoteSubscription = null;
|
|
702
|
+
this.pendingPriceSubscription = null;
|
|
633
703
|
if (!this.isConnected) return;
|
|
634
704
|
this.ws?.send(JSON.stringify({ type: "unsubscribe" }));
|
|
635
705
|
}
|
|
@@ -680,6 +750,9 @@ var K256WebSocketClient = class {
|
|
|
680
750
|
if (this.pendingQuoteSubscription) {
|
|
681
751
|
this.sendQuoteSubscription(this.pendingQuoteSubscription);
|
|
682
752
|
}
|
|
753
|
+
if (this.pendingPriceSubscription) {
|
|
754
|
+
this.sendPriceSubscription(this.pendingPriceSubscription);
|
|
755
|
+
}
|
|
683
756
|
this.config.onConnect?.();
|
|
684
757
|
resolve();
|
|
685
758
|
};
|
|
@@ -779,6 +852,21 @@ var K256WebSocketClient = class {
|
|
|
779
852
|
case "quote_subscribed":
|
|
780
853
|
this.config.onQuoteSubscribed?.(decoded);
|
|
781
854
|
break;
|
|
855
|
+
case "price_update":
|
|
856
|
+
this.config.onPriceUpdate?.(decoded);
|
|
857
|
+
break;
|
|
858
|
+
case "price_batch":
|
|
859
|
+
this.config.onPriceBatch?.(decoded);
|
|
860
|
+
for (const entry of decoded.data) {
|
|
861
|
+
this.config.onPriceUpdate?.({ type: "price_update", data: entry });
|
|
862
|
+
}
|
|
863
|
+
break;
|
|
864
|
+
case "price_snapshot":
|
|
865
|
+
this.config.onPriceSnapshot?.(decoded);
|
|
866
|
+
for (const entry of decoded.data) {
|
|
867
|
+
this.config.onPriceUpdate?.({ type: "price_update", data: entry });
|
|
868
|
+
}
|
|
869
|
+
break;
|
|
782
870
|
case "heartbeat":
|
|
783
871
|
this.lastHeartbeatTime = Date.now();
|
|
784
872
|
this.resetHeartbeatTimeout();
|
|
@@ -839,6 +927,18 @@ var K256WebSocketClient = class {
|
|
|
839
927
|
};
|
|
840
928
|
this.ws?.send(JSON.stringify(msg));
|
|
841
929
|
}
|
|
930
|
+
sendPriceSubscription(options) {
|
|
931
|
+
const json = JSON.stringify({
|
|
932
|
+
tokens: options.tokens,
|
|
933
|
+
thresholdBps: options.thresholdBps ?? 10
|
|
934
|
+
});
|
|
935
|
+
const encoder = new TextEncoder();
|
|
936
|
+
const jsonBytes = encoder.encode(json);
|
|
937
|
+
const buf = new Uint8Array(1 + jsonBytes.length);
|
|
938
|
+
buf[0] = MessageType.SubscribePrice;
|
|
939
|
+
buf.set(jsonBytes, 1);
|
|
940
|
+
this.ws?.send(buf);
|
|
941
|
+
}
|
|
842
942
|
setState(state) {
|
|
843
943
|
if (this._state !== state) {
|
|
844
944
|
const prevState = this._state;
|
|
@@ -1009,6 +1109,11 @@ function readU16(view, o) {
|
|
|
1009
1109
|
o.v += 2;
|
|
1010
1110
|
return val;
|
|
1011
1111
|
}
|
|
1112
|
+
function readF64(view, o) {
|
|
1113
|
+
const val = view.getFloat64(o.v, true);
|
|
1114
|
+
o.v += 8;
|
|
1115
|
+
return val;
|
|
1116
|
+
}
|
|
1012
1117
|
function readU8(view, o) {
|
|
1013
1118
|
const val = view.getUint8(o.v);
|
|
1014
1119
|
o.v += 1;
|
|
@@ -1067,12 +1172,16 @@ function readGossipPeer(view, data, o) {
|
|
|
1067
1172
|
lastVote: readU64(view, o),
|
|
1068
1173
|
rootSlot: readU64(view, o),
|
|
1069
1174
|
wallclock: readU64(view, o),
|
|
1070
|
-
// Geo/ASN enrichment from
|
|
1175
|
+
// Geo/ASN enrichment from MaxMind GeoLite2 (server-side)
|
|
1071
1176
|
countryCode: readVecU8AsString(view, data, o),
|
|
1072
1177
|
continentCode: readVecU8AsString(view, data, o),
|
|
1073
1178
|
asn: readVecU8AsString(view, data, o),
|
|
1074
1179
|
asName: readVecU8AsString(view, data, o),
|
|
1075
|
-
|
|
1180
|
+
city: readVecU8AsString(view, data, o),
|
|
1181
|
+
region: readVecU8AsString(view, data, o),
|
|
1182
|
+
latitude: readF64(view, o),
|
|
1183
|
+
longitude: readF64(view, o),
|
|
1184
|
+
timezone: readVecU8AsString(view, data, o)
|
|
1076
1185
|
};
|
|
1077
1186
|
}
|
|
1078
1187
|
function readGossipPeerVec(view, data, o) {
|
|
@@ -1503,6 +1612,7 @@ exports.base58Encode = base58Encode;
|
|
|
1503
1612
|
exports.decodeLeaderMessage = decodeLeaderMessage;
|
|
1504
1613
|
exports.decodeMessage = decodeMessage;
|
|
1505
1614
|
exports.decodePoolUpdateBatch = decodePoolUpdateBatch;
|
|
1615
|
+
exports.decodePriceEntries = decodePriceEntries;
|
|
1506
1616
|
exports.isValidPubkey = isValidPubkey;
|
|
1507
1617
|
//# sourceMappingURL=index.cjs.map
|
|
1508
1618
|
//# sourceMappingURL=index.cjs.map
|