@perena/vault-sdk 1.0.71 → 1.0.72

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.d.ts CHANGED
@@ -15781,9 +15781,12 @@ interface FetchJupiterUsdPricesOptions {
15781
15781
  * interface.
15782
15782
  */
15783
15783
 
15784
- type JupiterPriceSourceOptions = FetchJupiterUsdPricesOptions;
15784
+ interface JupiterPriceSourceOptions extends FetchJupiterUsdPricesOptions {
15785
+ cacheTtlMs?: number;
15786
+ }
15785
15787
  declare class JupiterPriceSource implements PriceSource {
15786
15788
  private readonly opts;
15789
+ private readonly cache;
15787
15790
  constructor(opts?: JupiterPriceSourceOptions);
15788
15791
  fetchUsdPrices(mints: Address[]): Promise<Record<string, number>>;
15789
15792
  }
package/dist/index.js CHANGED
@@ -24312,6 +24312,8 @@ var JupiterSwapClient = class {
24312
24312
  // ../jupiter/src/priceApi.ts
24313
24313
  var BATCH_SIZE = 50;
24314
24314
  var DEFAULT_RETRIES = 6;
24315
+ var RATE_LIMIT_BASE_DELAY_MS = 1e3;
24316
+ var RATE_LIMIT_MAX_DELAY_MS = 8e3;
24315
24317
  function chunk(items, size) {
24316
24318
  const out = [];
24317
24319
  for (let i = 0; i < items.length; i += size) {
@@ -24319,6 +24321,23 @@ function chunk(items, size) {
24319
24321
  }
24320
24322
  return out;
24321
24323
  }
24324
+ var JupiterRateLimitError = class extends Error {
24325
+ constructor(message2, retryAfterMs) {
24326
+ super(message2);
24327
+ this.retryAfterMs = retryAfterMs;
24328
+ }
24329
+ };
24330
+ function parseRetryAfterMs(header) {
24331
+ if (!header) return void 0;
24332
+ const seconds = Number(header);
24333
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
24334
+ const date = Date.parse(header);
24335
+ return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
24336
+ }
24337
+ function rateLimitDelayMs(err, attempt) {
24338
+ const backoff = RATE_LIMIT_BASE_DELAY_MS * 2 ** attempt;
24339
+ return Math.min(err.retryAfterMs ?? backoff, RATE_LIMIT_MAX_DELAY_MS);
24340
+ }
24322
24341
  async function withRetry(fn, attempts) {
24323
24342
  let lastErr;
24324
24343
  for (let i = 0; i < attempts; i += 1) {
@@ -24326,6 +24345,11 @@ async function withRetry(fn, attempts) {
24326
24345
  return await fn();
24327
24346
  } catch (err) {
24328
24347
  lastErr = err;
24348
+ if (err instanceof JupiterRateLimitError && i < attempts - 1) {
24349
+ await new Promise(
24350
+ (resolve) => setTimeout(resolve, rateLimitDelayMs(err, i))
24351
+ );
24352
+ }
24329
24353
  }
24330
24354
  }
24331
24355
  throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
@@ -24341,6 +24365,12 @@ async function fetchJupiterUsdPrices(mints2, opts = {}) {
24341
24365
  (batch) => withRetry(async () => {
24342
24366
  const url = `${baseUrl}?ids=${batch.join(",")}`;
24343
24367
  const res = await fetchFn(url);
24368
+ if (res.status === 429) {
24369
+ throw new JupiterRateLimitError(
24370
+ `Jupiter price API 429 for ${url}`,
24371
+ parseRetryAfterMs(res.headers.get("retry-after"))
24372
+ );
24373
+ }
24344
24374
  if (!res.ok) {
24345
24375
  throw new Error(`Jupiter price API ${res.status} for ${url}`);
24346
24376
  }
@@ -24365,12 +24395,33 @@ async function fetchJupiterUsdPrices(mints2, opts = {}) {
24365
24395
  }
24366
24396
 
24367
24397
  // src/services/consensusOracle/sources/jupiterPriceSource.ts
24398
+ var DEFAULT_CACHE_TTL_MS = 6e4;
24368
24399
  var JupiterPriceSource = class {
24369
24400
  constructor(opts = {}) {
24370
24401
  this.opts = opts;
24402
+ this.cache = /* @__PURE__ */ new Map();
24371
24403
  }
24372
24404
  async fetchUsdPrices(mints2) {
24373
- return fetchJupiterUsdPrices(mints2, this.opts);
24405
+ const { cacheTtlMs = DEFAULT_CACHE_TTL_MS, ...fetchOpts } = this.opts;
24406
+ const unique = [...new Set(mints2.map((mint) => mint.toString()))];
24407
+ const isFresh2 = (mint) => {
24408
+ const cached = this.cache.get(mint);
24409
+ return !!cached && Date.now() - cached.fetchedAt <= cacheTtlMs;
24410
+ };
24411
+ const missing = unique.filter((mint) => !isFresh2(mint));
24412
+ if (missing.length > 0) {
24413
+ const fetched = await fetchJupiterUsdPrices(missing, fetchOpts);
24414
+ const fetchedAt = Date.now();
24415
+ for (const [mint, price] of Object.entries(fetched)) {
24416
+ this.cache.set(mint, { price, fetchedAt });
24417
+ }
24418
+ }
24419
+ const prices = {};
24420
+ for (const mint of unique) {
24421
+ const cached = this.cache.get(mint);
24422
+ if (cached && isFresh2(mint)) prices[mint] = cached.price;
24423
+ }
24424
+ return prices;
24374
24425
  }
24375
24426
  };
24376
24427
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perena/vault-sdk",
3
- "version": "1.0.71",
3
+ "version": "1.0.72",
4
4
  "description": "Vault program helpers for Bankineco integrations.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",