@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.
@@ -53,6 +53,11 @@ function readU16(view, o) {
53
53
  o.v += 2;
54
54
  return val;
55
55
  }
56
+ function readF64(view, o) {
57
+ const val = view.getFloat64(o.v, true);
58
+ o.v += 8;
59
+ return val;
60
+ }
56
61
  function readU8(view, o) {
57
62
  const val = view.getUint8(o.v);
58
63
  o.v += 1;
@@ -111,12 +116,16 @@ function readGossipPeer(view, data, o) {
111
116
  lastVote: readU64(view, o),
112
117
  rootSlot: readU64(view, o),
113
118
  wallclock: readU64(view, o),
114
- // Geo/ASN enrichment from IPinfo Lite MMDB (server-side)
119
+ // Geo/ASN enrichment from MaxMind GeoLite2 (server-side)
115
120
  countryCode: readVecU8AsString(view, data, o),
116
121
  continentCode: readVecU8AsString(view, data, o),
117
122
  asn: readVecU8AsString(view, data, o),
118
123
  asName: readVecU8AsString(view, data, o),
119
- asDomain: readVecU8AsString(view, data, o)
124
+ city: readVecU8AsString(view, data, o),
125
+ region: readVecU8AsString(view, data, o),
126
+ latitude: readF64(view, o),
127
+ longitude: readF64(view, o),
128
+ timezone: readVecU8AsString(view, data, o)
120
129
  };
121
130
  }
122
131
  function readGossipPeerVec(view, data, o) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/base58.ts","../../src/leader-ws/decoder.ts","../../src/leader-ws/types.ts","../../src/leader-ws/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Base58 encoding utilities for Solana addresses\n * \n * Solana uses Base58 encoding (Bitcoin-style) for public keys and signatures.\n */\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Encode bytes to Base58 string (Solana address format)\n * \n * @param bytes - Uint8Array to encode\n * @returns Base58 encoded string\n * \n * @example\n * ```typescript\n * const pubkey = new Uint8Array([1, 2, 3, ...]);\n * const address = base58Encode(pubkey);\n * // \"EPjFWdd5...\"\n * ```\n */\nexport function base58Encode(bytes: Uint8Array): string {\n const digits = [0];\n \n for (let i = 0; i < bytes.length; i++) {\n let carry = bytes[i];\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n\n // Leading zeros\n let leadingZeros = '';\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n leadingZeros += '1';\n }\n\n return leadingZeros + digits.reverse().map(d => BASE58_ALPHABET[d]).join('');\n}\n\n/**\n * Decode Base58 string to bytes\n * \n * @param str - Base58 encoded string\n * @returns Uint8Array of decoded bytes\n * @throws Error if string contains invalid characters\n * \n * @example\n * ```typescript\n * const bytes = base58Decode(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\");\n * // Uint8Array(32) [...]\n * ```\n */\nexport function base58Decode(str: string): Uint8Array {\n if (str.length === 0) {\n return new Uint8Array(0);\n }\n\n // Count leading '1's (they represent leading zero bytes)\n let leadingZeros = 0;\n for (let i = 0; i < str.length && str[i] === '1'; i++) {\n leadingZeros++;\n }\n\n // Process remaining characters through base conversion\n const bytes = [0];\n for (let i = leadingZeros; i < str.length; i++) {\n const char = str[i];\n const value = BASE58_ALPHABET.indexOf(char);\n \n if (value === -1) {\n throw new Error(`Invalid Base58 character: ${char}`);\n }\n \n let carry = value;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n // Build result: leading zeros + converted bytes (reversed)\n bytes.reverse();\n \n // Handle case where input was all '1's (all leading zeros, no data to convert)\n // In this case, bytes is just [0] from initialization, which we should ignore\n if (leadingZeros > 0 && bytes.length === 1 && bytes[0] === 0) {\n // Input was all '1's, return that many zero bytes\n return new Uint8Array(leadingZeros);\n }\n \n // Remove leading zero from conversion if present (artifact of starting with [0])\n const startIdx = bytes.length > 1 && bytes[0] === 0 ? 1 : 0;\n \n const result = new Uint8Array(leadingZeros + bytes.length - startIdx);\n // Fill leading zeros\n for (let i = 0; i < leadingZeros; i++) {\n result[i] = 0;\n }\n // Copy converted bytes\n for (let i = startIdx; i < bytes.length; i++) {\n result[leadingZeros + i - startIdx] = bytes[i];\n }\n \n return result;\n}\n\n/**\n * Check if a string is a valid Solana public key (Base58, 32-44 chars)\n * \n * @param address - String to validate\n * @returns true if valid Solana pubkey format\n * \n * @example\n * ```typescript\n * isValidPubkey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\") // true\n * isValidPubkey(\"invalid\") // false\n * ```\n */\nexport function isValidPubkey(address: string): boolean {\n // Solana pubkeys are 32-44 characters in Base58\n if (address.length < 32 || address.length > 44) {\n return false;\n }\n\n // Check all characters are valid Base58\n for (const char of address) {\n if (!BASE58_ALPHABET.includes(char)) {\n return false;\n }\n }\n\n // Try to decode and verify length\n try {\n const bytes = base58Decode(address);\n return bytes.length === 32;\n } catch {\n return false;\n }\n}\n","/**\n * Binary message decoder for Leader Schedule WebSocket protocol\n * \n * Decodes wincode messages from the leader-schedule server into typed objects.\n * Matches K2 decoder pattern: manual DataView offset walking, little-endian.\n * \n * Wire format: [1 byte MessageType][N bytes wincode payload]\n */\n\nimport { base58Encode } from '../utils/base58';\nimport type {\n LeaderDecodedMessage,\n GossipPeer,\n} from './types';\n\n/** Message type tag constants (must match leader-schedule server protocol.rs) */\nexport const LeaderMessageTag = {\n Subscribe: 0x01,\n Subscribed: 0x02,\n LeaderSchedule: 0x10,\n GossipSnapshot: 0x11,\n GossipDiff: 0x12,\n SlotUpdate: 0x13,\n RoutingHealth: 0x14,\n SkipEvent: 0x15,\n IpChange: 0x16,\n Heartbeat: 0xFD,\n Ping: 0xFE,\n Error: 0xFF,\n} as const;\n\n/** Mutable offset tracker for sequential reading */\ntype Offset = { v: number };\n\n/** Read a wincode u64 (little-endian) */\nfunction readU64(view: DataView, o: Offset): number {\n const val = Number(view.getBigUint64(o.v, true));\n o.v += 8;\n return val;\n}\n\n/** Read a wincode u32 (little-endian) */\nfunction readU32(view: DataView, o: Offset): number {\n const val = view.getUint32(o.v, true);\n o.v += 4;\n return val;\n}\n\n/** Read a wincode u16 (little-endian) */\nfunction readU16(view: DataView, o: Offset): number {\n const val = view.getUint16(o.v, true);\n o.v += 2;\n return val;\n}\n\n/** Read a wincode u8 */\nfunction readU8(view: DataView, o: Offset): number {\n const val = view.getUint8(o.v);\n o.v += 1;\n return val;\n}\n\n/** Read a wincode bool */\nfunction readBool(view: DataView, o: Offset): boolean {\n return readU8(view, o) !== 0;\n}\n\n/** Read a [u8; 32] pubkey as base58 string */\nfunction readPubkey(data: ArrayBuffer, o: Offset): string {\n const bytes = new Uint8Array(data, o.v, 32);\n o.v += 32;\n return base58Encode(bytes);\n}\n\n/** Read a wincode Vec<u8> as string */\nfunction readVecU8AsString(view: DataView, data: ArrayBuffer, o: Offset): string {\n const len = readU64(view, o);\n const bytes = new Uint8Array(data, o.v, len);\n o.v += len;\n return new TextDecoder().decode(bytes);\n}\n\n/** Read a wincode Option<SocketAddrWire>: tag + ip[16] + port:u16 + is_ipv4:bool */\nfunction readOptSocketAddr(view: DataView, o: Offset): string | null {\n const tag = readU8(view, o);\n if (tag === 0) return null;\n const ipBytes = new Uint8Array(view.buffer, view.byteOffset + o.v, 16);\n o.v += 16;\n const port = readU16(view, o);\n const isIpv4 = readBool(view, o);\n if (isIpv4) {\n return `${ipBytes[12]}.${ipBytes[13]}.${ipBytes[14]}.${ipBytes[15]}:${port}`;\n }\n return `[ipv6]:${port}`;\n}\n\n/** Read a wincode Vec<[u8;32]> as base58 string array */\nfunction readPubkeyVec(view: DataView, data: ArrayBuffer, o: Offset): string[] {\n const count = readU64(view, o);\n const keys: string[] = [];\n for (let i = 0; i < count; i++) {\n keys.push(readPubkey(data, o));\n }\n return keys;\n}\n\n/** Read a single GossipPeer from wincode (field names match REST /gossip/peer/:id) */\nfunction readGossipPeer(view: DataView, data: ArrayBuffer, o: Offset): GossipPeer {\n return {\n identity: readPubkey(data, o),\n tpuQuic: readOptSocketAddr(view, o),\n tpuUdp: readOptSocketAddr(view, o),\n tpuForwardsQuic: readOptSocketAddr(view, o),\n tpuForwardsUdp: readOptSocketAddr(view, o),\n tpuVote: readOptSocketAddr(view, o),\n tpuVoteQuic: readOptSocketAddr(view, o),\n gossipAddr: readOptSocketAddr(view, o),\n shredVersion: readU16(view, o),\n version: readVecU8AsString(view, data, o),\n stake: readU64(view, o),\n commission: readU8(view, o),\n isDelinquent: readBool(view, o),\n voteAccount: readPubkey(data, o),\n lastVote: readU64(view, o),\n rootSlot: readU64(view, o),\n wallclock: readU64(view, o),\n // Geo/ASN enrichment from IPinfo Lite MMDB (server-side)\n countryCode: readVecU8AsString(view, data, o),\n continentCode: readVecU8AsString(view, data, o),\n asn: readVecU8AsString(view, data, o),\n asName: readVecU8AsString(view, data, o),\n asDomain: readVecU8AsString(view, data, o),\n };\n}\n\n/** Read a wincode Vec<GossipPeer> */\nfunction readGossipPeerVec(view: DataView, data: ArrayBuffer, o: Offset): GossipPeer[] {\n const count = readU64(view, o);\n const peers: GossipPeer[] = [];\n for (let i = 0; i < count; i++) {\n peers.push(readGossipPeer(view, data, o));\n }\n return peers;\n}\n\n/**\n * Decode a binary WebSocket message from the leader-schedule server.\n * \n * @param data - Raw binary data from WebSocket\n * @returns Decoded message or null if unrecognized type\n */\nexport function decodeLeaderMessage(data: ArrayBuffer): LeaderDecodedMessage | null {\n const view = new DataView(data);\n if (data.byteLength < 1) return null;\n\n const msgType = view.getUint8(0);\n const payload = data.slice(1);\n const pv = new DataView(payload);\n\n switch (msgType) {\n case LeaderMessageTag.Subscribed: {\n const text = new TextDecoder().decode(payload);\n try {\n return { type: 'subscribed', data: JSON.parse(text) };\n } catch {\n return null;\n }\n }\n\n case LeaderMessageTag.Error: {\n return { type: 'error', data: { message: new TextDecoder().decode(payload) } };\n }\n\n case LeaderMessageTag.SlotUpdate: {\n if (payload.byteLength < 48) return null;\n const o: Offset = { v: 0 };\n return {\n type: 'slot_update',\n kind: 'snapshot',\n data: {\n slot: readU64(pv, o),\n leader: readPubkey(payload, o),\n blockHeight: readU64(pv, o),\n },\n };\n }\n\n case LeaderMessageTag.Heartbeat: {\n if (payload.byteLength < 24) return null;\n const o: Offset = { v: 0 };\n return {\n type: 'heartbeat',\n kind: 'snapshot',\n data: {\n timestampMs: readU64(pv, o),\n currentSlot: readU64(pv, o),\n connectedClients: readU32(pv, o),\n gossipPeers: readU32(pv, o),\n },\n };\n }\n\n case LeaderMessageTag.SkipEvent: {\n if (payload.byteLength < 48) return null;\n const o: Offset = { v: 0 };\n return {\n type: 'skip_event',\n kind: 'event',\n key: 'leader',\n data: {\n slot: readU64(pv, o),\n leader: readPubkey(payload, o),\n assigned: readU32(pv, o),\n produced: readU32(pv, o),\n },\n };\n }\n\n case LeaderMessageTag.RoutingHealth: {\n if (payload.byteLength < 8) return null;\n try {\n const o: Offset = { v: 0 };\n const leadersTotal = readU32(pv, o);\n const leadersInGossip = readU32(pv, o);\n const leadersMissingGossip = readPubkeyVec(pv, payload, o);\n const leadersWithoutTpuQuic = readPubkeyVec(pv, payload, o);\n const leadersDelinquent = readPubkeyVec(pv, payload, o);\n return {\n type: 'routing_health',\n kind: 'snapshot',\n data: {\n leadersTotal,\n leadersInGossip,\n leadersMissingGossip,\n leadersWithoutTpuQuic,\n leadersDelinquent,\n coverage: `${leadersTotal > 0 ? (leadersInGossip / leadersTotal * 100).toFixed(1) : 0}%`,\n },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.IpChange: {\n if (payload.byteLength < 32) return null;\n try {\n const o: Offset = { v: 0 };\n const identity = readPubkey(payload, o);\n const oldIp = readVecU8AsString(pv, payload, o);\n const newIp = readVecU8AsString(pv, payload, o);\n const timestampMs = readU64(pv, o);\n return {\n type: 'ip_change',\n kind: 'event',\n key: 'identity',\n data: { identity, oldIp, newIp, timestampMs },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.GossipSnapshot: {\n if (payload.byteLength < 8) return null;\n try {\n const o: Offset = { v: 0 };\n const timestampMs = readU64(pv, o);\n const peers = readGossipPeerVec(pv, payload, o);\n return {\n type: 'gossip_snapshot',\n kind: 'snapshot',\n key: 'identity',\n data: { timestampMs, count: peers.length, peers },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.GossipDiff: {\n if (payload.byteLength < 8) return null;\n try {\n const o: Offset = { v: 0 };\n const timestampMs = readU64(pv, o);\n const added = readGossipPeerVec(pv, payload, o);\n const removed = readPubkeyVec(pv, payload, o);\n const updated = readGossipPeerVec(pv, payload, o);\n return {\n type: 'gossip_diff',\n kind: 'diff',\n key: 'identity',\n data: { timestampMs, added, removed, updated },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.LeaderSchedule: {\n if (payload.byteLength < 16) return null;\n try {\n const o: Offset = { v: 0 };\n const epoch = readU64(pv, o);\n const slotsInEpoch = readU64(pv, o);\n const validatorCount = readU64(pv, o);\n const schedule: Array<{ identity: string; slots: number; slotIndices: number[] }> = [];\n for (let i = 0; i < validatorCount; i++) {\n const identity = readPubkey(payload, o);\n const slotCount = readU64(pv, o);\n const slotIndices: number[] = [];\n for (let j = 0; j < slotCount; j++) {\n slotIndices.push(readU32(pv, o));\n }\n schedule.push({ identity, slots: slotIndices.length, slotIndices });\n }\n return {\n type: 'leader_schedule',\n kind: 'snapshot',\n data: { epoch, slotsInEpoch, validators: schedule.length, schedule },\n };\n } catch { return null; }\n }\n\n default:\n return null;\n }\n}\n","/**\n * Leader Schedule WebSocket message types and interfaces\n * \n * The leader-schedule WS uses wincode binary protocol (matching K2 pattern).\n * Wire format: [1-byte tag][wincode payload]\n * Every decoded message has:\n * - type: message type name\n * - kind: \"snapshot\" (full state) | \"diff\" (merge into snapshot) | \"event\" (append-only)\n * - key: primary key field for merging (on diff/event types)\n * - data: typed payload\n * \n * @see https://k256.xyz/docs/leader-schedule\n */\n\n/**\n * Leader Schedule WebSocket channels\n */\nexport const LeaderChannel = {\n /** Full epoch leader schedule (on connect + epoch change) */\n LeaderSchedule: 'leader_schedule',\n /** Gossip peers (snapshot on connect, then diffs) */\n Gossip: 'gossip',\n /** Real-time slot updates with current leader */\n Slots: 'slots',\n /** Skip events, IP changes, routing health */\n Alerts: 'alerts',\n} as const;\n\nexport type LeaderChannelValue = typeof LeaderChannel[keyof typeof LeaderChannel];\n\n/** All available channels */\nexport const ALL_LEADER_CHANNELS: LeaderChannelValue[] = [\n LeaderChannel.LeaderSchedule,\n LeaderChannel.Gossip,\n LeaderChannel.Slots,\n LeaderChannel.Alerts,\n];\n\n/**\n * Message kind — tells you how to consume the message\n */\nexport type MessageKind = 'snapshot' | 'diff' | 'event';\n\n// ═══════════════════════════════════════════════════════════════════════\n// Message Interfaces\n// ═══════════════════════════════════════════════════════════════════════\n\n/** Protocol schema entry (included in subscribed handshake) */\nexport interface MessageSchemaEntry {\n type: string;\n tag: string;\n kind: MessageKind;\n key?: string;\n description: string;\n}\n\n/** Subscribed response — connection handshake */\nexport interface LeaderSubscribedMessage {\n type: 'subscribed';\n data: {\n channels: string[];\n currentSlot: number;\n epoch: number;\n schema: MessageSchemaEntry[];\n };\n}\n\n/** Full epoch leader schedule (snapshot — replaces previous) */\nexport interface LeaderScheduleMessage {\n type: 'leader_schedule';\n kind: 'snapshot';\n data: {\n epoch: number;\n slotsInEpoch: number;\n validators: number;\n schedule: Array<{\n identity: string;\n slots: number;\n slotIndices: number[];\n }>;\n };\n}\n\n/** Gossip peer data (field names match REST /gossip/peer/:id for consistency) */\nexport interface GossipPeer {\n identity: string;\n tpuQuic: string | null;\n tpuUdp: string | null;\n tpuForwardsQuic: string | null;\n tpuForwardsUdp: string | null;\n tpuVote: string | null;\n tpuVoteQuic: string | null;\n gossipAddr: string | null;\n shredVersion: number;\n version: string;\n /** Activated stake in lamports (matches REST field name \"stake\") */\n stake: number;\n commission: number;\n isDelinquent: boolean;\n /** Vote account pubkey (matches REST field name \"voteAccount\") */\n voteAccount: string;\n lastVote: number;\n rootSlot: number;\n wallclock: number;\n /** ISO 3166 country code (e.g. \"US\", \"DE\") — from IPinfo Lite MMDB on server */\n countryCode: string;\n /** Two-letter continent code (e.g. \"NA\", \"EU\") */\n continentCode: string;\n /** ASN string (e.g. \"AS15169\") */\n asn: string;\n /** AS organization name (e.g. \"Google LLC\") */\n asName: string;\n /** AS organization domain (e.g. \"google.com\") */\n asDomain: string;\n}\n\n/** Full gossip peer list (snapshot — apply gossip_diff to keep current) */\nexport interface GossipSnapshotMessage {\n type: 'gossip_snapshot';\n kind: 'snapshot';\n key: 'identity';\n data: {\n timestampMs: number;\n count: number;\n peers: GossipPeer[];\n };\n}\n\n/** Incremental gossip changes (diff — merge into snapshot using identity) */\nexport interface GossipDiffMessage {\n type: 'gossip_diff';\n kind: 'diff';\n key: 'identity';\n data: {\n timestampMs: number;\n added: GossipPeer[];\n removed: string[];\n updated: GossipPeer[];\n };\n}\n\n/** Current slot with leader identity (snapshot — each replaces previous) */\nexport interface SlotUpdateMessage {\n type: 'slot_update';\n kind: 'snapshot';\n data: {\n slot: number;\n leader: string;\n blockHeight: number;\n };\n}\n\n/** Routing health summary (snapshot — each replaces previous) */\nexport interface RoutingHealthMessage {\n type: 'routing_health';\n kind: 'snapshot';\n data: {\n leadersTotal: number;\n leadersInGossip: number;\n leadersMissingGossip: string[];\n leadersWithoutTpuQuic: string[];\n leadersDelinquent: string[];\n coverage: string;\n };\n}\n\n/** Block production stats per validator (event — cumulative) */\nexport interface SkipEventMessage {\n type: 'skip_event';\n kind: 'event';\n key: 'leader';\n data: {\n slot: number;\n leader: string;\n assigned: number;\n produced: number;\n };\n}\n\n/** Validator IP address change (event) */\nexport interface IpChangeMessage {\n type: 'ip_change';\n kind: 'event';\n key: 'identity';\n data: {\n identity: string;\n oldIp: string;\n newIp: string;\n timestampMs: number;\n };\n}\n\n/** Server heartbeat (snapshot — each replaces previous) */\nexport interface LeaderHeartbeatMessage {\n type: 'heartbeat';\n kind: 'snapshot';\n data: {\n timestampMs: number;\n currentSlot: number;\n connectedClients: number;\n gossipPeers: number;\n };\n}\n\n/** Error from server */\nexport interface LeaderErrorMessage {\n type: 'error';\n data: {\n message: string;\n };\n}\n\n/** Union of all leader-schedule message types */\nexport type LeaderDecodedMessage =\n | LeaderSubscribedMessage\n | LeaderScheduleMessage\n | GossipSnapshotMessage\n | GossipDiffMessage\n | SlotUpdateMessage\n | RoutingHealthMessage\n | SkipEventMessage\n | IpChangeMessage\n | LeaderHeartbeatMessage\n | LeaderErrorMessage;\n","/**\n * Leader Schedule WebSocket Client\n * \n * Connects to the K256 leader-schedule service via the Gateway.\n * Binary mode by default (wincode protocol, matching K2 pattern).\n * JSON mode opt-in via mode: 'json' (gateway decodes wincode to JSON).\n * \n * @example\n * ```typescript\n * import { LeaderWebSocketClient } from '@k256/sdk/leader-ws';\n * \n * const client = new LeaderWebSocketClient({\n * apiKey: 'your-api-key',\n * onSlotUpdate: (msg) => console.log('Slot:', msg.data.slot, 'Leader:', msg.data.leader),\n * onRoutingHealth: (msg) => console.log('Coverage:', msg.data.coverage),\n * onGossipDiff: (msg) => console.log('Peers changed:', msg.data.added.length, 'added'),\n * });\n * \n * await client.connect();\n * ```\n */\n\nimport { decodeLeaderMessage } from './decoder';\nimport {\n ALL_LEADER_CHANNELS,\n type LeaderChannelValue,\n type LeaderDecodedMessage,\n type LeaderSubscribedMessage,\n type LeaderScheduleMessage,\n type GossipSnapshotMessage,\n type GossipDiffMessage,\n type SlotUpdateMessage,\n type RoutingHealthMessage,\n type SkipEventMessage,\n type IpChangeMessage,\n type LeaderHeartbeatMessage,\n type LeaderErrorMessage,\n} from './types';\n\n/**\n * Connection state\n */\nexport type ConnectionState = \n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'closed';\n\n/**\n * Leader WebSocket client configuration\n */\nexport interface LeaderWebSocketClientConfig {\n /** API key for authentication */\n apiKey: string;\n /** Gateway URL (default: wss://gateway.k256.xyz/v1/leader-ws) */\n url?: string;\n /** Message format: 'binary' (default, efficient) or 'json' (debugging via gateway) */\n mode?: 'binary' | 'json';\n /** Channels to subscribe to (default: all channels) */\n channels?: LeaderChannelValue[];\n \n // Reconnection settings\n /** Enable automatic reconnection (default: true) */\n autoReconnect?: boolean;\n /** Initial reconnect delay in ms (default: 1000) */\n reconnectDelayMs?: number;\n /** Max reconnect delay in ms (default: 30000) */\n maxReconnectDelayMs?: number;\n /** Max reconnect attempts (default: Infinity) */\n maxReconnectAttempts?: number;\n \n // Event callbacks\n /** Called when connection state changes */\n onStateChange?: (state: ConnectionState, prevState: ConnectionState) => void;\n /** Called on successful connection */\n onConnect?: () => void;\n /** Called on disconnection */\n onDisconnect?: (code: number, reason: string, wasClean: boolean) => void;\n /** Called on reconnection attempt */\n onReconnecting?: (attempt: number, delayMs: number) => void;\n /** Called on any error */\n onError?: (error: LeaderWebSocketError) => void;\n \n // Message callbacks\n /** Called on subscription confirmed (includes protocol schema) */\n onSubscribed?: (msg: LeaderSubscribedMessage) => void;\n /** Called on full leader schedule (snapshot — replaces previous) */\n onLeaderSchedule?: (msg: LeaderScheduleMessage) => void;\n /** Called on full gossip peer snapshot (snapshot — key: identity) */\n onGossipSnapshot?: (msg: GossipSnapshotMessage) => void;\n /** Called on gossip diff (diff — merge into snapshot using identity) */\n onGossipDiff?: (msg: GossipDiffMessage) => void;\n /** Called on slot update (snapshot — each replaces previous) */\n onSlotUpdate?: (msg: SlotUpdateMessage) => void;\n /** Called on routing health (snapshot — each replaces previous) */\n onRoutingHealth?: (msg: RoutingHealthMessage) => void;\n /** Called on skip event (event — block production stats) */\n onSkipEvent?: (msg: SkipEventMessage) => void;\n /** Called on IP change event */\n onIpChange?: (msg: IpChangeMessage) => void;\n /** Called on heartbeat (every 10s) */\n onHeartbeat?: (msg: LeaderHeartbeatMessage) => void;\n /** Called on any message (raw) */\n onMessage?: (msg: LeaderDecodedMessage) => void;\n}\n\n/**\n * Error codes for leader WebSocket\n */\nexport type LeaderErrorCode =\n | 'CONNECTION_FAILED'\n | 'CONNECTION_LOST'\n | 'AUTH_FAILED'\n | 'SERVER_ERROR'\n | 'INVALID_MESSAGE'\n | 'RECONNECT_FAILED';\n\n/**\n * WebSocket error with context\n */\nexport class LeaderWebSocketError extends Error {\n constructor(\n public readonly code: LeaderErrorCode,\n message: string,\n public readonly closeCode?: number,\n public readonly closeReason?: string,\n ) {\n super(message);\n this.name = 'LeaderWebSocketError';\n }\n\n get isRecoverable(): boolean {\n return this.code !== 'AUTH_FAILED';\n }\n}\n\n/**\n * Leader Schedule WebSocket Client\n * \n * Connects to the leader-schedule service via the Gateway.\n * Binary mode by default (wincode protocol). JSON mode opt-in via gateway.\n * Automatically subscribes to configured channels on connect/reconnect.\n */\nexport class LeaderWebSocketClient {\n private ws: WebSocket | null = null;\n private readonly config: Required<Pick<LeaderWebSocketClientConfig,\n 'apiKey' | 'url' | 'mode' | 'channels' | 'autoReconnect' | 'reconnectDelayMs' | 'maxReconnectDelayMs' | 'maxReconnectAttempts'\n >> & LeaderWebSocketClientConfig;\n \n private _state: ConnectionState = 'disconnected';\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private isIntentionallyClosed = false;\n\n /** Current connection state */\n get state(): ConnectionState { return this._state; }\n\n /** Whether currently connected */\n get isConnected(): boolean {\n return this._state === 'connected' && this.ws?.readyState === WebSocket.OPEN;\n }\n\n constructor(config: LeaderWebSocketClientConfig) {\n this.config = {\n url: 'wss://gateway.k256.xyz/v1/leader-ws',\n mode: 'binary',\n channels: ALL_LEADER_CHANNELS,\n autoReconnect: true,\n reconnectDelayMs: 1000,\n maxReconnectDelayMs: 30000,\n maxReconnectAttempts: Infinity,\n ...config,\n };\n }\n\n /**\n * Connect to the leader-schedule WebSocket\n */\n async connect(): Promise<void> {\n if (this._state === 'connected' || this._state === 'connecting') return;\n \n this.isIntentionallyClosed = false;\n this.setState('connecting');\n\n return new Promise((resolve, reject) => {\n try {\n const url = `${this.config.url}?apiKey=${encodeURIComponent(this.config.apiKey)}`;\n this.ws = new WebSocket(url);\n \n // Binary mode needs arraybuffer\n if (this.config.mode === 'binary') {\n this.ws.binaryType = 'arraybuffer';\n }\n\n this.ws.onopen = () => {\n this.setState('connected');\n this.reconnectAttempts = 0;\n \n if (this.config.mode === 'binary') {\n // Binary mode: send 0x01 tag + JSON payload\n const payload = JSON.stringify({ channels: this.config.channels });\n const bytes = new TextEncoder().encode(payload);\n const msg = new Uint8Array(1 + bytes.length);\n msg[0] = 0x01; // MSG_SUBSCRIBE\n msg.set(bytes, 1);\n this.ws!.send(msg.buffer);\n } else {\n // JSON mode: send text (gateway decodes wincode to JSON)\n this.ws!.send(JSON.stringify({\n type: 'subscribe',\n channels: this.config.channels,\n format: 'json',\n }));\n }\n \n this.config.onConnect?.();\n resolve();\n };\n\n this.ws.onmessage = (event) => {\n if (this.config.mode === 'binary' && event.data instanceof ArrayBuffer) {\n // Binary mode: decode wincode with SDK decoder\n const decoded = decodeLeaderMessage(event.data);\n if (decoded) {\n this.dispatchMessage(decoded);\n }\n } else if (typeof event.data === 'string') {\n // JSON mode: parse text frames from gateway\n this.handleJsonMessage(event.data);\n }\n };\n\n this.ws.onclose = (event) => {\n const wasConnected = this._state === 'connected';\n this.ws = null;\n \n if (this.isIntentionallyClosed) {\n this.setState('closed');\n this.config.onDisconnect?.(event.code, event.reason, event.wasClean);\n return;\n }\n \n this.config.onDisconnect?.(event.code, event.reason, event.wasClean);\n \n // Check for auth failure (don't reconnect)\n if (event.code === 1008 || event.code === 4001 || event.code === 4003) {\n this.setState('closed');\n this.config.onError?.(new LeaderWebSocketError(\n 'AUTH_FAILED', `Authentication failed: ${event.reason}`, event.code, event.reason\n ));\n if (!wasConnected) reject(new LeaderWebSocketError('AUTH_FAILED', event.reason, event.code));\n return;\n }\n \n // Auto-reconnect\n if (this.config.autoReconnect && this.reconnectAttempts < this.config.maxReconnectAttempts) {\n this.scheduleReconnect();\n } else {\n this.setState('disconnected');\n }\n \n if (!wasConnected) reject(new LeaderWebSocketError('CONNECTION_FAILED', 'WebSocket closed before connect'));\n };\n\n this.ws.onerror = () => {\n this.config.onError?.(new LeaderWebSocketError('CONNECTION_FAILED', 'WebSocket connection error'));\n };\n } catch (err) {\n this.setState('disconnected');\n reject(err);\n }\n });\n }\n\n /**\n * Disconnect from the WebSocket\n */\n disconnect(): void {\n this.isIntentionallyClosed = true;\n this.clearTimers();\n \n if (this.ws) {\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close(1000, 'Client disconnect');\n }\n this.ws = null;\n }\n \n this.setState('closed');\n }\n\n // ── Private ──\n\n /** Handle JSON text frame (from gateway JSON mode) */\n private handleJsonMessage(raw: string): void {\n try {\n const msg = JSON.parse(raw) as LeaderDecodedMessage;\n this.dispatchMessage(msg);\n } catch {\n this.config.onError?.(new LeaderWebSocketError('INVALID_MESSAGE', 'Failed to parse message'));\n }\n }\n\n /** Dispatch a decoded message to typed callbacks */\n private dispatchMessage(msg: LeaderDecodedMessage): void {\n switch (msg.type) {\n case 'subscribed':\n this.config.onSubscribed?.(msg as LeaderSubscribedMessage);\n break;\n case 'leader_schedule':\n this.config.onLeaderSchedule?.(msg as LeaderScheduleMessage);\n break;\n case 'gossip_snapshot':\n this.config.onGossipSnapshot?.(msg as GossipSnapshotMessage);\n break;\n case 'gossip_diff':\n this.config.onGossipDiff?.(msg as GossipDiffMessage);\n break;\n case 'slot_update':\n this.config.onSlotUpdate?.(msg as SlotUpdateMessage);\n break;\n case 'routing_health':\n this.config.onRoutingHealth?.(msg as RoutingHealthMessage);\n break;\n case 'skip_event':\n this.config.onSkipEvent?.(msg as SkipEventMessage);\n break;\n case 'ip_change':\n this.config.onIpChange?.(msg as IpChangeMessage);\n break;\n case 'heartbeat':\n this.config.onHeartbeat?.(msg as LeaderHeartbeatMessage);\n break;\n case 'error':\n this.config.onError?.(new LeaderWebSocketError(\n 'SERVER_ERROR', (msg as LeaderErrorMessage).data.message\n ));\n break;\n }\n \n // Generic handler\n this.config.onMessage?.(msg);\n }\n\n private setState(state: ConnectionState): void {\n const prev = this._state;\n if (prev === state) return;\n this._state = state;\n this.config.onStateChange?.(state, prev);\n }\n\n private scheduleReconnect(): void {\n this.setState('reconnecting');\n this.reconnectAttempts++;\n \n const delay = Math.min(\n this.config.reconnectDelayMs * Math.pow(2, this.reconnectAttempts - 1),\n this.config.maxReconnectDelayMs\n );\n \n this.config.onReconnecting?.(this.reconnectAttempts, delay);\n \n this.reconnectTimer = setTimeout(() => {\n this.connect().catch(() => {\n // Error handled in onclose/onerror\n });\n }, delay);\n }\n\n private clearTimers(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/base58.ts","../../src/leader-ws/decoder.ts","../../src/leader-ws/types.ts","../../src/leader-ws/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Base58 encoding utilities for Solana addresses\n * \n * Solana uses Base58 encoding (Bitcoin-style) for public keys and signatures.\n */\n\nconst BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n/**\n * Encode bytes to Base58 string (Solana address format)\n * \n * @param bytes - Uint8Array to encode\n * @returns Base58 encoded string\n * \n * @example\n * ```typescript\n * const pubkey = new Uint8Array([1, 2, 3, ...]);\n * const address = base58Encode(pubkey);\n * // \"EPjFWdd5...\"\n * ```\n */\nexport function base58Encode(bytes: Uint8Array): string {\n const digits = [0];\n \n for (let i = 0; i < bytes.length; i++) {\n let carry = bytes[i];\n for (let j = 0; j < digits.length; j++) {\n carry += digits[j] << 8;\n digits[j] = carry % 58;\n carry = (carry / 58) | 0;\n }\n while (carry > 0) {\n digits.push(carry % 58);\n carry = (carry / 58) | 0;\n }\n }\n\n // Leading zeros\n let leadingZeros = '';\n for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {\n leadingZeros += '1';\n }\n\n return leadingZeros + digits.reverse().map(d => BASE58_ALPHABET[d]).join('');\n}\n\n/**\n * Decode Base58 string to bytes\n * \n * @param str - Base58 encoded string\n * @returns Uint8Array of decoded bytes\n * @throws Error if string contains invalid characters\n * \n * @example\n * ```typescript\n * const bytes = base58Decode(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\");\n * // Uint8Array(32) [...]\n * ```\n */\nexport function base58Decode(str: string): Uint8Array {\n if (str.length === 0) {\n return new Uint8Array(0);\n }\n\n // Count leading '1's (they represent leading zero bytes)\n let leadingZeros = 0;\n for (let i = 0; i < str.length && str[i] === '1'; i++) {\n leadingZeros++;\n }\n\n // Process remaining characters through base conversion\n const bytes = [0];\n for (let i = leadingZeros; i < str.length; i++) {\n const char = str[i];\n const value = BASE58_ALPHABET.indexOf(char);\n \n if (value === -1) {\n throw new Error(`Invalid Base58 character: ${char}`);\n }\n \n let carry = value;\n for (let j = 0; j < bytes.length; j++) {\n carry += bytes[j] * 58;\n bytes[j] = carry & 0xff;\n carry >>= 8;\n }\n while (carry > 0) {\n bytes.push(carry & 0xff);\n carry >>= 8;\n }\n }\n\n // Build result: leading zeros + converted bytes (reversed)\n bytes.reverse();\n \n // Handle case where input was all '1's (all leading zeros, no data to convert)\n // In this case, bytes is just [0] from initialization, which we should ignore\n if (leadingZeros > 0 && bytes.length === 1 && bytes[0] === 0) {\n // Input was all '1's, return that many zero bytes\n return new Uint8Array(leadingZeros);\n }\n \n // Remove leading zero from conversion if present (artifact of starting with [0])\n const startIdx = bytes.length > 1 && bytes[0] === 0 ? 1 : 0;\n \n const result = new Uint8Array(leadingZeros + bytes.length - startIdx);\n // Fill leading zeros\n for (let i = 0; i < leadingZeros; i++) {\n result[i] = 0;\n }\n // Copy converted bytes\n for (let i = startIdx; i < bytes.length; i++) {\n result[leadingZeros + i - startIdx] = bytes[i];\n }\n \n return result;\n}\n\n/**\n * Check if a string is a valid Solana public key (Base58, 32-44 chars)\n * \n * @param address - String to validate\n * @returns true if valid Solana pubkey format\n * \n * @example\n * ```typescript\n * isValidPubkey(\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\") // true\n * isValidPubkey(\"invalid\") // false\n * ```\n */\nexport function isValidPubkey(address: string): boolean {\n // Solana pubkeys are 32-44 characters in Base58\n if (address.length < 32 || address.length > 44) {\n return false;\n }\n\n // Check all characters are valid Base58\n for (const char of address) {\n if (!BASE58_ALPHABET.includes(char)) {\n return false;\n }\n }\n\n // Try to decode and verify length\n try {\n const bytes = base58Decode(address);\n return bytes.length === 32;\n } catch {\n return false;\n }\n}\n","/**\n * Binary message decoder for Leader Schedule WebSocket protocol\n * \n * Decodes wincode messages from the leader-schedule server into typed objects.\n * Matches K2 decoder pattern: manual DataView offset walking, little-endian.\n * \n * Wire format: [1 byte MessageType][N bytes wincode payload]\n */\n\nimport { base58Encode } from '../utils/base58';\nimport type {\n LeaderDecodedMessage,\n GossipPeer,\n} from './types';\n\n/** Message type tag constants (must match leader-schedule server protocol.rs) */\nexport const LeaderMessageTag = {\n Subscribe: 0x01,\n Subscribed: 0x02,\n LeaderSchedule: 0x10,\n GossipSnapshot: 0x11,\n GossipDiff: 0x12,\n SlotUpdate: 0x13,\n RoutingHealth: 0x14,\n SkipEvent: 0x15,\n IpChange: 0x16,\n Heartbeat: 0xFD,\n Ping: 0xFE,\n Error: 0xFF,\n} as const;\n\n/** Mutable offset tracker for sequential reading */\ntype Offset = { v: number };\n\n/** Read a wincode u64 (little-endian) */\nfunction readU64(view: DataView, o: Offset): number {\n const val = Number(view.getBigUint64(o.v, true));\n o.v += 8;\n return val;\n}\n\n/** Read a wincode u32 (little-endian) */\nfunction readU32(view: DataView, o: Offset): number {\n const val = view.getUint32(o.v, true);\n o.v += 4;\n return val;\n}\n\n/** Read a wincode u16 (little-endian) */\nfunction readU16(view: DataView, o: Offset): number {\n const val = view.getUint16(o.v, true);\n o.v += 2;\n return val;\n}\n\n/** Read a wincode f64 (little-endian IEEE 754) */\nfunction readF64(view: DataView, o: Offset): number {\n const val = view.getFloat64(o.v, true);\n o.v += 8;\n return val;\n}\n\n/** Read a wincode u8 */\nfunction readU8(view: DataView, o: Offset): number {\n const val = view.getUint8(o.v);\n o.v += 1;\n return val;\n}\n\n/** Read a wincode bool */\nfunction readBool(view: DataView, o: Offset): boolean {\n return readU8(view, o) !== 0;\n}\n\n/** Read a [u8; 32] pubkey as base58 string */\nfunction readPubkey(data: ArrayBuffer, o: Offset): string {\n const bytes = new Uint8Array(data, o.v, 32);\n o.v += 32;\n return base58Encode(bytes);\n}\n\n/** Read a wincode Vec<u8> as string */\nfunction readVecU8AsString(view: DataView, data: ArrayBuffer, o: Offset): string {\n const len = readU64(view, o);\n const bytes = new Uint8Array(data, o.v, len);\n o.v += len;\n return new TextDecoder().decode(bytes);\n}\n\n/** Read a wincode Option<SocketAddrWire>: tag + ip[16] + port:u16 + is_ipv4:bool */\nfunction readOptSocketAddr(view: DataView, o: Offset): string | null {\n const tag = readU8(view, o);\n if (tag === 0) return null;\n const ipBytes = new Uint8Array(view.buffer, view.byteOffset + o.v, 16);\n o.v += 16;\n const port = readU16(view, o);\n const isIpv4 = readBool(view, o);\n if (isIpv4) {\n return `${ipBytes[12]}.${ipBytes[13]}.${ipBytes[14]}.${ipBytes[15]}:${port}`;\n }\n return `[ipv6]:${port}`;\n}\n\n/** Read a wincode Vec<[u8;32]> as base58 string array */\nfunction readPubkeyVec(view: DataView, data: ArrayBuffer, o: Offset): string[] {\n const count = readU64(view, o);\n const keys: string[] = [];\n for (let i = 0; i < count; i++) {\n keys.push(readPubkey(data, o));\n }\n return keys;\n}\n\n/** Read a single GossipPeer from wincode (field names match REST /gossip/peer/:id) */\nfunction readGossipPeer(view: DataView, data: ArrayBuffer, o: Offset): GossipPeer {\n return {\n identity: readPubkey(data, o),\n tpuQuic: readOptSocketAddr(view, o),\n tpuUdp: readOptSocketAddr(view, o),\n tpuForwardsQuic: readOptSocketAddr(view, o),\n tpuForwardsUdp: readOptSocketAddr(view, o),\n tpuVote: readOptSocketAddr(view, o),\n tpuVoteQuic: readOptSocketAddr(view, o),\n gossipAddr: readOptSocketAddr(view, o),\n shredVersion: readU16(view, o),\n version: readVecU8AsString(view, data, o),\n stake: readU64(view, o),\n commission: readU8(view, o),\n isDelinquent: readBool(view, o),\n voteAccount: readPubkey(data, o),\n lastVote: readU64(view, o),\n rootSlot: readU64(view, o),\n wallclock: readU64(view, o),\n // Geo/ASN enrichment from MaxMind GeoLite2 (server-side)\n countryCode: readVecU8AsString(view, data, o),\n continentCode: readVecU8AsString(view, data, o),\n asn: readVecU8AsString(view, data, o),\n asName: readVecU8AsString(view, data, o),\n city: readVecU8AsString(view, data, o),\n region: readVecU8AsString(view, data, o),\n latitude: readF64(view, o),\n longitude: readF64(view, o),\n timezone: readVecU8AsString(view, data, o),\n };\n}\n\n/** Read a wincode Vec<GossipPeer> */\nfunction readGossipPeerVec(view: DataView, data: ArrayBuffer, o: Offset): GossipPeer[] {\n const count = readU64(view, o);\n const peers: GossipPeer[] = [];\n for (let i = 0; i < count; i++) {\n peers.push(readGossipPeer(view, data, o));\n }\n return peers;\n}\n\n/**\n * Decode a binary WebSocket message from the leader-schedule server.\n * \n * @param data - Raw binary data from WebSocket\n * @returns Decoded message or null if unrecognized type\n */\nexport function decodeLeaderMessage(data: ArrayBuffer): LeaderDecodedMessage | null {\n const view = new DataView(data);\n if (data.byteLength < 1) return null;\n\n const msgType = view.getUint8(0);\n const payload = data.slice(1);\n const pv = new DataView(payload);\n\n switch (msgType) {\n case LeaderMessageTag.Subscribed: {\n const text = new TextDecoder().decode(payload);\n try {\n return { type: 'subscribed', data: JSON.parse(text) };\n } catch {\n return null;\n }\n }\n\n case LeaderMessageTag.Error: {\n return { type: 'error', data: { message: new TextDecoder().decode(payload) } };\n }\n\n case LeaderMessageTag.SlotUpdate: {\n if (payload.byteLength < 48) return null;\n const o: Offset = { v: 0 };\n return {\n type: 'slot_update',\n kind: 'snapshot',\n data: {\n slot: readU64(pv, o),\n leader: readPubkey(payload, o),\n blockHeight: readU64(pv, o),\n },\n };\n }\n\n case LeaderMessageTag.Heartbeat: {\n if (payload.byteLength < 24) return null;\n const o: Offset = { v: 0 };\n return {\n type: 'heartbeat',\n kind: 'snapshot',\n data: {\n timestampMs: readU64(pv, o),\n currentSlot: readU64(pv, o),\n connectedClients: readU32(pv, o),\n gossipPeers: readU32(pv, o),\n },\n };\n }\n\n case LeaderMessageTag.SkipEvent: {\n if (payload.byteLength < 48) return null;\n const o: Offset = { v: 0 };\n return {\n type: 'skip_event',\n kind: 'event',\n key: 'leader',\n data: {\n slot: readU64(pv, o),\n leader: readPubkey(payload, o),\n assigned: readU32(pv, o),\n produced: readU32(pv, o),\n },\n };\n }\n\n case LeaderMessageTag.RoutingHealth: {\n if (payload.byteLength < 8) return null;\n try {\n const o: Offset = { v: 0 };\n const leadersTotal = readU32(pv, o);\n const leadersInGossip = readU32(pv, o);\n const leadersMissingGossip = readPubkeyVec(pv, payload, o);\n const leadersWithoutTpuQuic = readPubkeyVec(pv, payload, o);\n const leadersDelinquent = readPubkeyVec(pv, payload, o);\n return {\n type: 'routing_health',\n kind: 'snapshot',\n data: {\n leadersTotal,\n leadersInGossip,\n leadersMissingGossip,\n leadersWithoutTpuQuic,\n leadersDelinquent,\n coverage: `${leadersTotal > 0 ? (leadersInGossip / leadersTotal * 100).toFixed(1) : 0}%`,\n },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.IpChange: {\n if (payload.byteLength < 32) return null;\n try {\n const o: Offset = { v: 0 };\n const identity = readPubkey(payload, o);\n const oldIp = readVecU8AsString(pv, payload, o);\n const newIp = readVecU8AsString(pv, payload, o);\n const timestampMs = readU64(pv, o);\n return {\n type: 'ip_change',\n kind: 'event',\n key: 'identity',\n data: { identity, oldIp, newIp, timestampMs },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.GossipSnapshot: {\n if (payload.byteLength < 8) return null;\n try {\n const o: Offset = { v: 0 };\n const timestampMs = readU64(pv, o);\n const peers = readGossipPeerVec(pv, payload, o);\n return {\n type: 'gossip_snapshot',\n kind: 'snapshot',\n key: 'identity',\n data: { timestampMs, count: peers.length, peers },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.GossipDiff: {\n if (payload.byteLength < 8) return null;\n try {\n const o: Offset = { v: 0 };\n const timestampMs = readU64(pv, o);\n const added = readGossipPeerVec(pv, payload, o);\n const removed = readPubkeyVec(pv, payload, o);\n const updated = readGossipPeerVec(pv, payload, o);\n return {\n type: 'gossip_diff',\n kind: 'diff',\n key: 'identity',\n data: { timestampMs, added, removed, updated },\n };\n } catch { return null; }\n }\n\n case LeaderMessageTag.LeaderSchedule: {\n if (payload.byteLength < 16) return null;\n try {\n const o: Offset = { v: 0 };\n const epoch = readU64(pv, o);\n const slotsInEpoch = readU64(pv, o);\n const validatorCount = readU64(pv, o);\n const schedule: Array<{ identity: string; slots: number; slotIndices: number[] }> = [];\n for (let i = 0; i < validatorCount; i++) {\n const identity = readPubkey(payload, o);\n const slotCount = readU64(pv, o);\n const slotIndices: number[] = [];\n for (let j = 0; j < slotCount; j++) {\n slotIndices.push(readU32(pv, o));\n }\n schedule.push({ identity, slots: slotIndices.length, slotIndices });\n }\n return {\n type: 'leader_schedule',\n kind: 'snapshot',\n data: { epoch, slotsInEpoch, validators: schedule.length, schedule },\n };\n } catch { return null; }\n }\n\n default:\n return null;\n }\n}\n","/**\n * Leader Schedule WebSocket message types and interfaces\n * \n * The leader-schedule WS uses wincode binary protocol (matching K2 pattern).\n * Wire format: [1-byte tag][wincode payload]\n * Every decoded message has:\n * - type: message type name\n * - kind: \"snapshot\" (full state) | \"diff\" (merge into snapshot) | \"event\" (append-only)\n * - key: primary key field for merging (on diff/event types)\n * - data: typed payload\n * \n * @see https://k256.xyz/docs/leader-schedule\n */\n\n/**\n * Leader Schedule WebSocket channels\n */\nexport const LeaderChannel = {\n /** Full epoch leader schedule (on connect + epoch change) */\n LeaderSchedule: 'leader_schedule',\n /** Gossip peers (snapshot on connect, then diffs) */\n Gossip: 'gossip',\n /** Real-time slot updates with current leader */\n Slots: 'slots',\n /** Skip events, IP changes, routing health */\n Alerts: 'alerts',\n} as const;\n\nexport type LeaderChannelValue = typeof LeaderChannel[keyof typeof LeaderChannel];\n\n/** All available channels */\nexport const ALL_LEADER_CHANNELS: LeaderChannelValue[] = [\n LeaderChannel.LeaderSchedule,\n LeaderChannel.Gossip,\n LeaderChannel.Slots,\n LeaderChannel.Alerts,\n];\n\n/**\n * Message kind — tells you how to consume the message\n */\nexport type MessageKind = 'snapshot' | 'diff' | 'event';\n\n// ═══════════════════════════════════════════════════════════════════════\n// Message Interfaces\n// ═══════════════════════════════════════════════════════════════════════\n\n/** Protocol schema entry (included in subscribed handshake) */\nexport interface MessageSchemaEntry {\n type: string;\n tag: string;\n kind: MessageKind;\n key?: string;\n description: string;\n}\n\n/** Subscribed response — connection handshake */\nexport interface LeaderSubscribedMessage {\n type: 'subscribed';\n data: {\n channels: string[];\n currentSlot: number;\n epoch: number;\n schema: MessageSchemaEntry[];\n };\n}\n\n/** Full epoch leader schedule (snapshot — replaces previous) */\nexport interface LeaderScheduleMessage {\n type: 'leader_schedule';\n kind: 'snapshot';\n data: {\n epoch: number;\n slotsInEpoch: number;\n validators: number;\n schedule: Array<{\n identity: string;\n slots: number;\n slotIndices: number[];\n }>;\n };\n}\n\n/** Gossip peer data (field names match REST /gossip/peer/:id for consistency) */\nexport interface GossipPeer {\n identity: string;\n tpuQuic: string | null;\n tpuUdp: string | null;\n tpuForwardsQuic: string | null;\n tpuForwardsUdp: string | null;\n tpuVote: string | null;\n tpuVoteQuic: string | null;\n gossipAddr: string | null;\n shredVersion: number;\n version: string;\n /** Activated stake in lamports (matches REST field name \"stake\") */\n stake: number;\n commission: number;\n isDelinquent: boolean;\n /** Vote account pubkey (matches REST field name \"voteAccount\") */\n voteAccount: string;\n lastVote: number;\n rootSlot: number;\n wallclock: number;\n /** ISO 3166 country code (e.g. \"US\", \"DE\") — from MaxMind GeoLite2 on server */\n countryCode: string;\n /** Two-letter continent code (e.g. \"NA\", \"EU\") */\n continentCode: string;\n /** ASN string (e.g. \"AS15169\") */\n asn: string;\n /** AS organization name (e.g. \"Google LLC\") */\n asName: string;\n /** City name (e.g. \"Frankfurt\") — from MaxMind GeoLite2 on server */\n city: string;\n /** Region/state name (e.g. \"California\") */\n region: string;\n /** Latitude */\n latitude: number;\n /** Longitude */\n longitude: number;\n /** IANA timezone (e.g. \"America/Los_Angeles\") */\n timezone: string;\n}\n\n/** Full gossip peer list (snapshot — apply gossip_diff to keep current) */\nexport interface GossipSnapshotMessage {\n type: 'gossip_snapshot';\n kind: 'snapshot';\n key: 'identity';\n data: {\n timestampMs: number;\n count: number;\n peers: GossipPeer[];\n };\n}\n\n/** Incremental gossip changes (diff — merge into snapshot using identity) */\nexport interface GossipDiffMessage {\n type: 'gossip_diff';\n kind: 'diff';\n key: 'identity';\n data: {\n timestampMs: number;\n added: GossipPeer[];\n removed: string[];\n updated: GossipPeer[];\n };\n}\n\n/** Current slot with leader identity (snapshot — each replaces previous) */\nexport interface SlotUpdateMessage {\n type: 'slot_update';\n kind: 'snapshot';\n data: {\n slot: number;\n leader: string;\n blockHeight: number;\n };\n}\n\n/** Routing health summary (snapshot — each replaces previous) */\nexport interface RoutingHealthMessage {\n type: 'routing_health';\n kind: 'snapshot';\n data: {\n leadersTotal: number;\n leadersInGossip: number;\n leadersMissingGossip: string[];\n leadersWithoutTpuQuic: string[];\n leadersDelinquent: string[];\n coverage: string;\n };\n}\n\n/** Block production stats per validator (event — cumulative) */\nexport interface SkipEventMessage {\n type: 'skip_event';\n kind: 'event';\n key: 'leader';\n data: {\n slot: number;\n leader: string;\n assigned: number;\n produced: number;\n };\n}\n\n/** Validator IP address change (event) */\nexport interface IpChangeMessage {\n type: 'ip_change';\n kind: 'event';\n key: 'identity';\n data: {\n identity: string;\n oldIp: string;\n newIp: string;\n timestampMs: number;\n };\n}\n\n/** Server heartbeat (snapshot — each replaces previous) */\nexport interface LeaderHeartbeatMessage {\n type: 'heartbeat';\n kind: 'snapshot';\n data: {\n timestampMs: number;\n currentSlot: number;\n connectedClients: number;\n gossipPeers: number;\n };\n}\n\n/** Error from server */\nexport interface LeaderErrorMessage {\n type: 'error';\n data: {\n message: string;\n };\n}\n\n/** Union of all leader-schedule message types */\nexport type LeaderDecodedMessage =\n | LeaderSubscribedMessage\n | LeaderScheduleMessage\n | GossipSnapshotMessage\n | GossipDiffMessage\n | SlotUpdateMessage\n | RoutingHealthMessage\n | SkipEventMessage\n | IpChangeMessage\n | LeaderHeartbeatMessage\n | LeaderErrorMessage;\n","/**\n * Leader Schedule WebSocket Client\n * \n * Connects to the K256 leader-schedule service via the Gateway.\n * Binary mode by default (wincode protocol, matching K2 pattern).\n * JSON mode opt-in via mode: 'json' (gateway decodes wincode to JSON).\n * \n * @example\n * ```typescript\n * import { LeaderWebSocketClient } from '@k256/sdk/leader-ws';\n * \n * const client = new LeaderWebSocketClient({\n * apiKey: 'your-api-key',\n * onSlotUpdate: (msg) => console.log('Slot:', msg.data.slot, 'Leader:', msg.data.leader),\n * onRoutingHealth: (msg) => console.log('Coverage:', msg.data.coverage),\n * onGossipDiff: (msg) => console.log('Peers changed:', msg.data.added.length, 'added'),\n * });\n * \n * await client.connect();\n * ```\n */\n\nimport { decodeLeaderMessage } from './decoder';\nimport {\n ALL_LEADER_CHANNELS,\n type LeaderChannelValue,\n type LeaderDecodedMessage,\n type LeaderSubscribedMessage,\n type LeaderScheduleMessage,\n type GossipSnapshotMessage,\n type GossipDiffMessage,\n type SlotUpdateMessage,\n type RoutingHealthMessage,\n type SkipEventMessage,\n type IpChangeMessage,\n type LeaderHeartbeatMessage,\n type LeaderErrorMessage,\n} from './types';\n\n/**\n * Connection state\n */\nexport type ConnectionState = \n | 'disconnected'\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'closed';\n\n/**\n * Leader WebSocket client configuration\n */\nexport interface LeaderWebSocketClientConfig {\n /** API key for authentication */\n apiKey: string;\n /** Gateway URL (default: wss://gateway.k256.xyz/v1/leader-ws) */\n url?: string;\n /** Message format: 'binary' (default, efficient) or 'json' (debugging via gateway) */\n mode?: 'binary' | 'json';\n /** Channels to subscribe to (default: all channels) */\n channels?: LeaderChannelValue[];\n \n // Reconnection settings\n /** Enable automatic reconnection (default: true) */\n autoReconnect?: boolean;\n /** Initial reconnect delay in ms (default: 1000) */\n reconnectDelayMs?: number;\n /** Max reconnect delay in ms (default: 30000) */\n maxReconnectDelayMs?: number;\n /** Max reconnect attempts (default: Infinity) */\n maxReconnectAttempts?: number;\n \n // Event callbacks\n /** Called when connection state changes */\n onStateChange?: (state: ConnectionState, prevState: ConnectionState) => void;\n /** Called on successful connection */\n onConnect?: () => void;\n /** Called on disconnection */\n onDisconnect?: (code: number, reason: string, wasClean: boolean) => void;\n /** Called on reconnection attempt */\n onReconnecting?: (attempt: number, delayMs: number) => void;\n /** Called on any error */\n onError?: (error: LeaderWebSocketError) => void;\n \n // Message callbacks\n /** Called on subscription confirmed (includes protocol schema) */\n onSubscribed?: (msg: LeaderSubscribedMessage) => void;\n /** Called on full leader schedule (snapshot — replaces previous) */\n onLeaderSchedule?: (msg: LeaderScheduleMessage) => void;\n /** Called on full gossip peer snapshot (snapshot — key: identity) */\n onGossipSnapshot?: (msg: GossipSnapshotMessage) => void;\n /** Called on gossip diff (diff — merge into snapshot using identity) */\n onGossipDiff?: (msg: GossipDiffMessage) => void;\n /** Called on slot update (snapshot — each replaces previous) */\n onSlotUpdate?: (msg: SlotUpdateMessage) => void;\n /** Called on routing health (snapshot — each replaces previous) */\n onRoutingHealth?: (msg: RoutingHealthMessage) => void;\n /** Called on skip event (event — block production stats) */\n onSkipEvent?: (msg: SkipEventMessage) => void;\n /** Called on IP change event */\n onIpChange?: (msg: IpChangeMessage) => void;\n /** Called on heartbeat (every 10s) */\n onHeartbeat?: (msg: LeaderHeartbeatMessage) => void;\n /** Called on any message (raw) */\n onMessage?: (msg: LeaderDecodedMessage) => void;\n}\n\n/**\n * Error codes for leader WebSocket\n */\nexport type LeaderErrorCode =\n | 'CONNECTION_FAILED'\n | 'CONNECTION_LOST'\n | 'AUTH_FAILED'\n | 'SERVER_ERROR'\n | 'INVALID_MESSAGE'\n | 'RECONNECT_FAILED';\n\n/**\n * WebSocket error with context\n */\nexport class LeaderWebSocketError extends Error {\n constructor(\n public readonly code: LeaderErrorCode,\n message: string,\n public readonly closeCode?: number,\n public readonly closeReason?: string,\n ) {\n super(message);\n this.name = 'LeaderWebSocketError';\n }\n\n get isRecoverable(): boolean {\n return this.code !== 'AUTH_FAILED';\n }\n}\n\n/**\n * Leader Schedule WebSocket Client\n * \n * Connects to the leader-schedule service via the Gateway.\n * Binary mode by default (wincode protocol). JSON mode opt-in via gateway.\n * Automatically subscribes to configured channels on connect/reconnect.\n */\nexport class LeaderWebSocketClient {\n private ws: WebSocket | null = null;\n private readonly config: Required<Pick<LeaderWebSocketClientConfig,\n 'apiKey' | 'url' | 'mode' | 'channels' | 'autoReconnect' | 'reconnectDelayMs' | 'maxReconnectDelayMs' | 'maxReconnectAttempts'\n >> & LeaderWebSocketClientConfig;\n \n private _state: ConnectionState = 'disconnected';\n private reconnectAttempts = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private isIntentionallyClosed = false;\n\n /** Current connection state */\n get state(): ConnectionState { return this._state; }\n\n /** Whether currently connected */\n get isConnected(): boolean {\n return this._state === 'connected' && this.ws?.readyState === WebSocket.OPEN;\n }\n\n constructor(config: LeaderWebSocketClientConfig) {\n this.config = {\n url: 'wss://gateway.k256.xyz/v1/leader-ws',\n mode: 'binary',\n channels: ALL_LEADER_CHANNELS,\n autoReconnect: true,\n reconnectDelayMs: 1000,\n maxReconnectDelayMs: 30000,\n maxReconnectAttempts: Infinity,\n ...config,\n };\n }\n\n /**\n * Connect to the leader-schedule WebSocket\n */\n async connect(): Promise<void> {\n if (this._state === 'connected' || this._state === 'connecting') return;\n \n this.isIntentionallyClosed = false;\n this.setState('connecting');\n\n return new Promise((resolve, reject) => {\n try {\n const url = `${this.config.url}?apiKey=${encodeURIComponent(this.config.apiKey)}`;\n this.ws = new WebSocket(url);\n \n // Binary mode needs arraybuffer\n if (this.config.mode === 'binary') {\n this.ws.binaryType = 'arraybuffer';\n }\n\n this.ws.onopen = () => {\n this.setState('connected');\n this.reconnectAttempts = 0;\n \n if (this.config.mode === 'binary') {\n // Binary mode: send 0x01 tag + JSON payload\n const payload = JSON.stringify({ channels: this.config.channels });\n const bytes = new TextEncoder().encode(payload);\n const msg = new Uint8Array(1 + bytes.length);\n msg[0] = 0x01; // MSG_SUBSCRIBE\n msg.set(bytes, 1);\n this.ws!.send(msg.buffer);\n } else {\n // JSON mode: send text (gateway decodes wincode to JSON)\n this.ws!.send(JSON.stringify({\n type: 'subscribe',\n channels: this.config.channels,\n format: 'json',\n }));\n }\n \n this.config.onConnect?.();\n resolve();\n };\n\n this.ws.onmessage = (event) => {\n if (this.config.mode === 'binary' && event.data instanceof ArrayBuffer) {\n // Binary mode: decode wincode with SDK decoder\n const decoded = decodeLeaderMessage(event.data);\n if (decoded) {\n this.dispatchMessage(decoded);\n }\n } else if (typeof event.data === 'string') {\n // JSON mode: parse text frames from gateway\n this.handleJsonMessage(event.data);\n }\n };\n\n this.ws.onclose = (event) => {\n const wasConnected = this._state === 'connected';\n this.ws = null;\n \n if (this.isIntentionallyClosed) {\n this.setState('closed');\n this.config.onDisconnect?.(event.code, event.reason, event.wasClean);\n return;\n }\n \n this.config.onDisconnect?.(event.code, event.reason, event.wasClean);\n \n // Check for auth failure (don't reconnect)\n if (event.code === 1008 || event.code === 4001 || event.code === 4003) {\n this.setState('closed');\n this.config.onError?.(new LeaderWebSocketError(\n 'AUTH_FAILED', `Authentication failed: ${event.reason}`, event.code, event.reason\n ));\n if (!wasConnected) reject(new LeaderWebSocketError('AUTH_FAILED', event.reason, event.code));\n return;\n }\n \n // Auto-reconnect\n if (this.config.autoReconnect && this.reconnectAttempts < this.config.maxReconnectAttempts) {\n this.scheduleReconnect();\n } else {\n this.setState('disconnected');\n }\n \n if (!wasConnected) reject(new LeaderWebSocketError('CONNECTION_FAILED', 'WebSocket closed before connect'));\n };\n\n this.ws.onerror = () => {\n this.config.onError?.(new LeaderWebSocketError('CONNECTION_FAILED', 'WebSocket connection error'));\n };\n } catch (err) {\n this.setState('disconnected');\n reject(err);\n }\n });\n }\n\n /**\n * Disconnect from the WebSocket\n */\n disconnect(): void {\n this.isIntentionallyClosed = true;\n this.clearTimers();\n \n if (this.ws) {\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close(1000, 'Client disconnect');\n }\n this.ws = null;\n }\n \n this.setState('closed');\n }\n\n // ── Private ──\n\n /** Handle JSON text frame (from gateway JSON mode) */\n private handleJsonMessage(raw: string): void {\n try {\n const msg = JSON.parse(raw) as LeaderDecodedMessage;\n this.dispatchMessage(msg);\n } catch {\n this.config.onError?.(new LeaderWebSocketError('INVALID_MESSAGE', 'Failed to parse message'));\n }\n }\n\n /** Dispatch a decoded message to typed callbacks */\n private dispatchMessage(msg: LeaderDecodedMessage): void {\n switch (msg.type) {\n case 'subscribed':\n this.config.onSubscribed?.(msg as LeaderSubscribedMessage);\n break;\n case 'leader_schedule':\n this.config.onLeaderSchedule?.(msg as LeaderScheduleMessage);\n break;\n case 'gossip_snapshot':\n this.config.onGossipSnapshot?.(msg as GossipSnapshotMessage);\n break;\n case 'gossip_diff':\n this.config.onGossipDiff?.(msg as GossipDiffMessage);\n break;\n case 'slot_update':\n this.config.onSlotUpdate?.(msg as SlotUpdateMessage);\n break;\n case 'routing_health':\n this.config.onRoutingHealth?.(msg as RoutingHealthMessage);\n break;\n case 'skip_event':\n this.config.onSkipEvent?.(msg as SkipEventMessage);\n break;\n case 'ip_change':\n this.config.onIpChange?.(msg as IpChangeMessage);\n break;\n case 'heartbeat':\n this.config.onHeartbeat?.(msg as LeaderHeartbeatMessage);\n break;\n case 'error':\n this.config.onError?.(new LeaderWebSocketError(\n 'SERVER_ERROR', (msg as LeaderErrorMessage).data.message\n ));\n break;\n }\n \n // Generic handler\n this.config.onMessage?.(msg);\n }\n\n private setState(state: ConnectionState): void {\n const prev = this._state;\n if (prev === state) return;\n this._state = state;\n this.config.onStateChange?.(state, prev);\n }\n\n private scheduleReconnect(): void {\n this.setState('reconnecting');\n this.reconnectAttempts++;\n \n const delay = Math.min(\n this.config.reconnectDelayMs * Math.pow(2, this.reconnectAttempts - 1),\n this.config.maxReconnectDelayMs\n );\n \n this.config.onReconnecting?.(this.reconnectAttempts, delay);\n \n this.reconnectTimer = setTimeout(() => {\n this.connect().catch(() => {\n // Error handled in onclose/onerror\n });\n }, delay);\n }\n\n private clearTimers(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n}\n"]}
@@ -85,7 +85,7 @@ interface GossipPeer {
85
85
  lastVote: number;
86
86
  rootSlot: number;
87
87
  wallclock: number;
88
- /** ISO 3166 country code (e.g. "US", "DE") — from IPinfo Lite MMDB on server */
88
+ /** ISO 3166 country code (e.g. "US", "DE") — from MaxMind GeoLite2 on server */
89
89
  countryCode: string;
90
90
  /** Two-letter continent code (e.g. "NA", "EU") */
91
91
  continentCode: string;
@@ -93,8 +93,16 @@ interface GossipPeer {
93
93
  asn: string;
94
94
  /** AS organization name (e.g. "Google LLC") */
95
95
  asName: string;
96
- /** AS organization domain (e.g. "google.com") */
97
- asDomain: string;
96
+ /** City name (e.g. "Frankfurt") — from MaxMind GeoLite2 on server */
97
+ city: string;
98
+ /** Region/state name (e.g. "California") */
99
+ region: string;
100
+ /** Latitude */
101
+ latitude: number;
102
+ /** Longitude */
103
+ longitude: number;
104
+ /** IANA timezone (e.g. "America/Los_Angeles") */
105
+ timezone: string;
98
106
  }
99
107
  /** Full gossip peer list (snapshot — apply gossip_diff to keep current) */
100
108
  interface GossipSnapshotMessage {
@@ -85,7 +85,7 @@ interface GossipPeer {
85
85
  lastVote: number;
86
86
  rootSlot: number;
87
87
  wallclock: number;
88
- /** ISO 3166 country code (e.g. "US", "DE") — from IPinfo Lite MMDB on server */
88
+ /** ISO 3166 country code (e.g. "US", "DE") — from MaxMind GeoLite2 on server */
89
89
  countryCode: string;
90
90
  /** Two-letter continent code (e.g. "NA", "EU") */
91
91
  continentCode: string;
@@ -93,8 +93,16 @@ interface GossipPeer {
93
93
  asn: string;
94
94
  /** AS organization name (e.g. "Google LLC") */
95
95
  asName: string;
96
- /** AS organization domain (e.g. "google.com") */
97
- asDomain: string;
96
+ /** City name (e.g. "Frankfurt") — from MaxMind GeoLite2 on server */
97
+ city: string;
98
+ /** Region/state name (e.g. "California") */
99
+ region: string;
100
+ /** Latitude */
101
+ latitude: number;
102
+ /** Longitude */
103
+ longitude: number;
104
+ /** IANA timezone (e.g. "America/Los_Angeles") */
105
+ timezone: string;
98
106
  }
99
107
  /** Full gossip peer list (snapshot — apply gossip_diff to keep current) */
100
108
  interface GossipSnapshotMessage {
@@ -51,6 +51,11 @@ function readU16(view, o) {
51
51
  o.v += 2;
52
52
  return val;
53
53
  }
54
+ function readF64(view, o) {
55
+ const val = view.getFloat64(o.v, true);
56
+ o.v += 8;
57
+ return val;
58
+ }
54
59
  function readU8(view, o) {
55
60
  const val = view.getUint8(o.v);
56
61
  o.v += 1;
@@ -109,12 +114,16 @@ function readGossipPeer(view, data, o) {
109
114
  lastVote: readU64(view, o),
110
115
  rootSlot: readU64(view, o),
111
116
  wallclock: readU64(view, o),
112
- // Geo/ASN enrichment from IPinfo Lite MMDB (server-side)
117
+ // Geo/ASN enrichment from MaxMind GeoLite2 (server-side)
113
118
  countryCode: readVecU8AsString(view, data, o),
114
119
  continentCode: readVecU8AsString(view, data, o),
115
120
  asn: readVecU8AsString(view, data, o),
116
121
  asName: readVecU8AsString(view, data, o),
117
- asDomain: readVecU8AsString(view, data, o)
122
+ city: readVecU8AsString(view, data, o),
123
+ region: readVecU8AsString(view, data, o),
124
+ latitude: readF64(view, o),
125
+ longitude: readF64(view, o),
126
+ timezone: readVecU8AsString(view, data, o)
118
127
  };
119
128
  }
120
129
  function readGossipPeerVec(view, data, o) {