-
Notifications
You must be signed in to change notification settings - Fork 300
feat(lazer/js/sdk): add REST endpoints and examples #3075
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
3e28b03
04b4bf4
728be08
44dd770
f9aa7e3
8bba790
dc3c953
859e363
bf0e141
c7b2ff6
51db2dd
56f0aef
4d98508
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* eslint-disable no-console */ | ||
|
||
import { displayParsedPrices } from "./util.js"; | ||
import { PythLazerClient } from "../src/index.js"; | ||
|
||
const client = await PythLazerClient.create({ | ||
token: "your-token-here", | ||
logger: console, | ||
}); | ||
|
||
// Example 1: Get latest price for BTC using feed IDs | ||
console.log("\n=== Example 1: Latest BTC price (requested with feed ID) ==="); | ||
const response1 = await client.get_latest_price({ | ||
priceFeedIds: [1], | ||
properties: ["price", "confidence", "exponent"], | ||
formats: [], | ||
jsonBinaryEncoding: "hex", | ||
parsed: true, | ||
channel: "fixed_rate@200ms", | ||
}); | ||
displayParsedPrices(response1); | ||
|
||
// Example 2: Get latest price using symbols | ||
console.log("\n=== Example 2: Latest ETH price (requested with symbols) ==="); | ||
const response2 = await client.get_latest_price({ | ||
priceFeedIds: [2], | ||
properties: ["price", "confidence", "exponent"], | ||
formats: [], | ||
parsed: true, | ||
channel: "real_time", | ||
}); | ||
displayParsedPrices(response2); | ||
|
||
// Example 3: Get historical price at specific timestamp | ||
console.log("\n=== Example 3: Historical BTC price at timestamp ==="); | ||
const timestamp = 1_754_348_458_565_000; | ||
console.log( | ||
`Requesting price from timestamp: ${timestamp.toString()} (${new Date(timestamp / 1000).toISOString()})`, | ||
); | ||
const response3 = await client.get_price({ | ||
timestamp: timestamp, | ||
priceFeedIds: [1], | ||
properties: ["price", "confidence", "exponent"], | ||
formats: [], | ||
parsed: true, | ||
channel: "real_time", | ||
}); | ||
displayParsedPrices(response3); |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* eslint-disable no-console */ | ||
/* eslint-disable @typescript-eslint/no-empty-function */ | ||
|
||
import { renderFeeds, refreshFeedDisplay } from "./util.js"; | ||
import type { JsonUpdate } from "../src/index.js"; | ||
import { PythLazerClient } from "../src/index.js"; | ||
|
||
// Ignore debug messages | ||
console.debug = () => {}; | ||
|
||
// Store feed data for in-place updates | ||
const feedData = new Map< | ||
string, | ||
{ | ||
priceFeedId: string | number; | ||
price: number; | ||
confidence: number | undefined; | ||
exponent: number; | ||
lastUpdate: Date; | ||
} | ||
>(); | ||
|
||
const client = await PythLazerClient.create({ | ||
token: "your-token-here", // Replace with your actual access token | ||
logger: console, // Optionally log operations (to the console in this case.) | ||
webSocketPoolConfig: { | ||
numConnections: 4, // Optionally specify number of parallel redundant connections to reduce the chance of dropped messages. The connections will round-robin across the provided URLs. Default is 4. | ||
onError: (error) => { | ||
console.error("WebSocket error:", error); | ||
}, | ||
// Optional configuration for resilient WebSocket connections | ||
rwsConfig: { | ||
heartbeatTimeoutDurationMs: 5000, // Optional heartbeat timeout duration in milliseconds | ||
maxRetryDelayMs: 1000, // Optional maximum retry delay in milliseconds | ||
logAfterRetryCount: 10, // Optional log after how many retries | ||
}, | ||
}, | ||
}); | ||
|
||
// Read and display messages from the Lazer stream | ||
client.addMessageListener((message) => { | ||
switch (message.type) { | ||
case "json": { | ||
if (message.value.type == "streamUpdated") { | ||
refreshFeedDisplay(message.value as JsonUpdate, feedData); | ||
} | ||
break; | ||
} | ||
case "binary": { | ||
// Print out the binary hex messages if you want: | ||
// if ("solana" in message.value) { | ||
// console.info("solana message:", message.value.solana?.toString("hex")); | ||
// } | ||
// if ("evm" in message.value) { | ||
// console.info("evm message:", message.value.evm?.toString("hex")); | ||
// } | ||
Comment on lines
+59
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Left it in as a hint for people who want to use the binary message |
||
break; | ||
} | ||
} | ||
}); | ||
|
||
// Monitor for all connections in the pool being down simultaneously (e.g. if the internet goes down) | ||
// The connections may still try to reconnect in the background. To shut down the client completely, call shutdown(). | ||
client.addAllConnectionsDownListener(() => { | ||
console.error("All connections are down!"); | ||
}); | ||
|
||
renderFeeds(feedData); | ||
|
||
// Create and remove one or more subscriptions on the fly | ||
client.subscribe({ | ||
type: "subscribe", | ||
subscriptionId: 1, | ||
priceFeedIds: [1, 2], | ||
properties: ["price"], | ||
formats: ["solana"], | ||
deliveryFormat: "binary", | ||
channel: "fixed_rate@200ms", | ||
parsed: false, | ||
jsonBinaryEncoding: "base64", | ||
}); | ||
client.subscribe({ | ||
type: "subscribe", | ||
subscriptionId: 2, | ||
priceFeedIds: [1, 2, 3, 4, 5], | ||
properties: ["price", "exponent", "publisherCount", "confidence"], | ||
formats: ["evm"], | ||
deliveryFormat: "json", | ||
channel: "fixed_rate@200ms", | ||
parsed: true, | ||
jsonBinaryEncoding: "hex", | ||
}); | ||
client.subscribe({ | ||
type: "subscribe", | ||
subscriptionId: 3, | ||
priceFeedIds: [1], | ||
properties: ["price", "confidence"], | ||
formats: ["solana"], | ||
deliveryFormat: "json", | ||
channel: "fixed_rate@200ms", | ||
parsed: true, | ||
jsonBinaryEncoding: "hex", | ||
}); | ||
|
||
await new Promise((resolve) => setTimeout(resolve, 30_000)); | ||
|
||
client.unsubscribe(1); | ||
client.unsubscribe(2); | ||
client.unsubscribe(3); | ||
|
||
process.stdout.write("\u001B[2J\u001B[H"); | ||
tejasbadadare marked this conversation as resolved.
Show resolved
Hide resolved
|
||
console.log("🛑 Shutting down Pyth Lazer demo after 30 seconds..."); | ||
console.log("👋 Goodbye!"); | ||
|
||
client.shutdown(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* eslint-disable no-console */ | ||
|
||
import { PythLazerClient } from "../src/index.js"; | ||
|
||
const client = await PythLazerClient.create({ | ||
token: "your-token-here", | ||
logger: console, | ||
}); | ||
|
||
// Example 1: Get latest price for BTC using feed IDs | ||
console.log("\n=== Example 1: Search feeds by name/symbol ==="); | ||
const response1 = await client.get_symbols({ query: "BTC" }); | ||
console.log(response1); | ||
|
||
// Example 2: Get latest price using symbols | ||
console.log("\n=== Example 2: Get feeds by asset type ==="); | ||
const response2 = await client.get_symbols({ | ||
asset_type: "equity", | ||
}); | ||
console.log(response2); | ||
|
||
// Example 3: Get feeds by asset type and query | ||
console.log("\n=== Example 3: Get feeds by asset type and name/symbol ==="); | ||
const response3 = await client.get_symbols({ | ||
asset_type: "equity", | ||
query: "AAPL", | ||
}); | ||
|
||
console.log(response3); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be doing this at a file level? I feel like we should respect the log level that is passed into the execution call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah there is no
console.setLevel
unfortunately, this is a common workaround to set "log level" when usingconsole
directly as a logger. Functionally its the same as passing in ats-log
instance or something, but again its just an example so didn't want to prescribe things like which logger to pass in.