Skip to content

switch from lite-api to api.jup.ag with API key auth#4

Open
odilitime wants to merge 38 commits into1.xfrom
odi-dev
Open

switch from lite-api to api.jup.ag with API key auth#4
odilitime wants to merge 38 commits into1.xfrom
odi-dev

Conversation

@odilitime
Copy link
Member

@odilitime odilitime commented Feb 11, 2026

lite-api.jup.ag no longer works; basic tier now requires an API key. Reads JUPITER_API_KEY from runtime settings and sends x-api-key header on all quote and swap requests. Also adds build.ts, tsconfig.build.json, expanded .gitignore, and various type annotation fixes.


Note

Medium Risk
Touches core swap/quote networking behavior and now hard-fails startup without an API key, so misconfiguration or queue/caching bugs could break trading flows; changes are localized to the Jupiter plugin and build tooling.

Overview
Migrates all Jupiter quote/swap traffic to https://api.jup.ag and requires JUPITER_API_KEY at service start, automatically injecting x-api-key headers and clearing credentials on stop.

Reworks request handling into a shared per-IP, 1 RPS serialized queue (quotes/swaps/metadata) with retry/backoff on 429, adds TTL+size-bounded route caching keyed by mint/amount/slippage, updates token metadata/markets/price lookups (including a new getCurrentPrices) and makes getHistoricalPrices fall back to a current snapshot.

Build tooling switches from tsup to a Bun build.ts runner plus tsconfig.build.json, and housekeeping updates include expanded .gitignore and a generated .prr/lessons.md file.

Written by Cursor Bugbot for commit b981558. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • API key–based authentication with queued, rate-limited request processing and route caching for repeated queries.
    • New Bun-based build runner and build configuration.
  • Improvements

    • Exponential-backoff retries, clearer consolidated error logging, and updated build flow that ensures TypeScript declarations.
  • Chores

    • Expanded ignore rules to cover build artifacts, env files, IDE/system caches, logs and temp files.
  • Tests

    • Added a test demonstrating failure handling for missing commands.
  • Documentation

    • Added internal PR review lessons file.

Greptile Overview

Greptile Summary

Migrates Jupiter API integration from lite-api.jup.ag to api.jup.ag with API key authentication via x-api-key header, sourced from JUPITER_API_KEY runtime setting.

Key Changes:

  • Adds getApiHeaders() function to inject x-api-key header when API key is configured
  • Updates base URL constant to https://api.jup.ag/swap/v1 for quote and swap endpoints
  • Improves TypeScript typing for queue handlers, quote responses, and cache utilities
  • Refines cache key to include amount parameter for better cache granularity
  • Replaces tsup build with custom Bun-based build.ts that runs ESM bundling + TypeScript declaration generation

Issues Found:

  • getTokenPair() and getHistoricalPrices() methods still call the old https://public.jupiterapi.com endpoints, which may not accept the new API key header
  • dev script references --watch flag, but build.ts doesn't implement watch mode
  • Dead code in build.ts (unreachable else branch due to if (true) condition)

Confidence Score: 3/5

  • Mostly safe to merge, but has endpoint inconsistencies that could cause runtime issues
  • Core quote/swap functionality properly migrated to new API with authentication, but two methods (getTokenPair, getHistoricalPrices) still use old endpoints that may not work. Build system changes are functional despite minor issues with watch mode and dead code.
  • Pay close attention to src/service.ts - verify that getTokenPair and getHistoricalPrices work with the old endpoint or need migration

Important Files Changed

Filename Overview
src/service.ts Updates to api.jup.ag with API key auth; two methods still use old public.jupiterapi.com endpoint
build.ts New Bun-based build script; contains unreachable dead code in conditional branch
package.json Switches from tsup to custom build.ts; dev script references unimplemented --watch flag

Sequence Diagram

sequenceDiagram
    participant Client as JupiterService
    participant API as api.jup.ag
    participant Queue as Request Queue
    
    Note over Client: Service starts, reads API key from settings
    Client->>Client: Load API key configuration
    
    Note over Client,API: Quote Request Flow
    Client->>Queue: quoteEnqueue(url)
    Queue->>Queue: Add to quotes queue
    Queue->>API: GET /swap/v1/quote (with auth header)
    API-->>Queue: Quote response
    Queue-->>Client: Return quote data
    
    Note over Client,API: Swap Request Flow
    Client->>Queue: swapEnqueue(url, payload)
    Queue->>Queue: Add to swaps queue
    Queue->>API: POST /swap/v1/swap (with auth header)
    API-->>Queue: Swap transaction data
    Queue-->>Client: Return swap data
    
    Note over Queue: Queues process at 1 req/sec<br/>with exponential backoff on 429
Loading

lite-api.jup.ag no longer works; basic tier now requires an API key.
Reads JUPITER_API_KEY from runtime settings and sends x-api-key header
on all quote and swap requests. Also adds build.ts, tsconfig.build.json,
expanded .gitignore, and various type annotation fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings February 11, 2026 00:58
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a Bun-based build orchestrator and tsconfig.build.json, expands .gitignore rules, introduces a Bun-oriented test file, adds PR-review lessons, and refactors src/service.ts to add API-key startup gating, shared rate-limit queues with retries/backoff, a TTL FIFO route cache, centralized API headers, and improved error logging.

Changes

Cohort / File(s) Summary
Build system
build.ts, package.json, tsconfig.build.json
Adds build.ts (Bun-based build orchestrator), updates package.json build script to bun run build.ts and adds engines.bun + typescript devDependency, and introduces tsconfig.build.json for dist output, declarations, and sourcemaps.
Jupiter service
src/service.ts
Large refactor: introduces module-level API key and startup gating, shared per-operation rate-limit queues (quotes/swaps/metadata) with retry/backoff, centralized getApiHeaders, TTL FIFO route cache with eviction, unified JUPITER_BASE_URL routing, and standardized error handling/logging. Adds private fields for routeCache and apiKey.
Repository ignore rules
.gitignore
Expands ignore list (build outputs, .tsbuildinfo, .turbo, env files, IDE folders, coverage, logs, caches, temp files, bundler artifacts, .pr-resolver-state.json); removes node_modules entry from Build outputs section.
Tests & scripts
test_fail.ts
Adds a Bun-targeted test script that runs a non-existent command to exercise failure handling; logs and exits with non-zero on error.
PR review notes
.prr/lessons.md
Adds auto-generated PR review lessons documenting concerns and recommended fixes specific to src/service.ts (instructional only, no code changes).

Sequence Diagram(s)

sequenceDiagram
    rect rgba(52,152,219,0.5)
    participant Client
    end
    rect rgba(46,204,113,0.5)
    participant JupiterService
    end
    rect rgba(241,196,15,0.5)
    participant RouteCache
    end
    rect rgba(155,89,182,0.5)
    participant RateLimitQueue
    end
    rect rgba(231,76,60,0.5)
    participant JupiterAPI
    end

    Client->>JupiterService: request quote/swap/metadata(params)
    JupiterService->>RouteCache: check cache(key)
    alt cache hit
        RouteCache-->>JupiterService: cached result
        JupiterService-->>Client: return cached result
    else cache miss
        JupiterService->>RateLimitQueue: enqueue request(params, apiKey, headers)
        RateLimitQueue-->>JupiterService: dequeue/process
        JupiterService->>JupiterAPI: HTTP request (with getApiHeaders)
        alt 429 or transient error
            JupiterAPI-->>RateLimitQueue: error
            RateLimitQueue->>RateLimitQueue: schedule retry (exponential backoff)
            RateLimitQueue-->>JupiterService: retry processed
            JupiterService->>JupiterAPI: retry request
        end
        JupiterAPI-->>JupiterService: response
        JupiterService->>RouteCache: set cache(key, response, ttl)
        JupiterService-->>Client: return response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 Bun warms my paws at break of day,
Queues hum softly while I hop and play.
Keys and caches guard the trail I roam,
Backoffs nudge retries till requests come home.
Hooray — this rabbit hops back to the code!

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: migrating from lite-api to api.jup.ag with API key authentication, which is the core objective reflected throughout the changeset.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into 1.x
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch odi-dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 11, 2026

Additional Comments (2)

src/service.ts
getTokenPair still uses the old https://public.jupiterapi.com endpoint which may not accept the new API key header


src/service.ts
getHistoricalPrices still uses the old https://public.jupiterapi.com endpoint which may not accept the new API key header

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/service.ts (2)

356-374: ⚠️ Potential issue | 🔴 Critical

Bug: outAmount is divided by input decimals instead of output decimals.

outAmount is denominated in the output token's atomic units (USDC with 6 decimals by default), but line 369 divides by 10 ** inputDecimals. For any input token whose decimals differ from the output token's (e.g., SOL with 9 decimals), the returned price will be off by orders of magnitude.

Example: 1 SOL → 150 USDC yields outAmount = 150_000_000, but 150_000_000 / 10^9 = 0.15 instead of the correct 150_000_000 / 10^6 = 150.

Proposed fix
   async getTokenPrice(
     tokenMint: string,
     quoteMint: string = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
-    inputDecimals: number = 6
+    inputDecimals: number = 6,
+    outputDecimals: number = 6
   ): Promise<number> {
     try {
       const baseAmount = 10 ** inputDecimals;
       const quote = await this.getQuote({
         inputMint: tokenMint,
         outputMint: quoteMint,
         amount: baseAmount,
         slippageBps: 50,
       });
-      return Number((quote as any).outAmount) / 10 ** inputDecimals;
+      return Number((quote as any).outAmount) / 10 ** outputDecimals;
     } catch (error) {

218-233: ⚠️ Potential issue | 🟡 Minor

Cache key uses raw amount but the API receives intAmount — key mismatch possible.

Line 218 parses amount to an integer (intAmount), but line 224 builds the cache key using the original amount. If amount is a float (e.g., 1000.5), the cache key will differ from what's actually queried, causing cache misses or stale hits for the truncated value.

Proposed fix
-      const key = inputMint + '_' + outputMint + '_' + amount
+      const key = inputMint + '_' + outputMint + '_' + intAmount
🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 15-16: The dev script is misleading because "dev": "bun run
build.ts --watch" passes --watch but build.ts doesn't handle it, and tsup
remains unused in devDependencies; either implement watch handling in build.ts
(detect the "--watch" flag in build.ts's argument parsing and start a
file-watcher or call the existing build loop when watch=true) or remove the
watch flag from package.json and delete the unused "tsup" entry from
devDependencies; locate references to the "build" and "dev" scripts in
package.json and the build logic in build.ts to add flag parsing (e.g., checking
process.argv for "--watch") or to simplify scripts and prune "tsup" from
devDependencies accordingly.

In `@src/service.ts`:
- Line 178: routeCache currently accumulates entries added by getQuote and never
evicts them; fix by applying a TTL and/or size cap when inserting and reading
from routeCache: use the existing setCacheExp/getCacheExp helpers to attach and
check expiration for entries stored under the composite key used in getQuote
(inputMint, outputMint, amount), and remove expired entries on access;
additionally implement a simple size cap (e.g., LRU or FIFO) in the same module
so when routeCache.length exceeds the limit you evict oldest entries—ensure the
logic is centralized around the routeCache field and the getQuote function so
all inserts and lookups respect TTL and cap.
- Around line 8-21: The module-level jupiterApiKey and import-time queue timers
cause global shared state and last-writer-wins behavior; move the API key and
header logic into the JupiterService instance (e.g., make jupiterApiKey an
instance property and convert getApiHeaders into an instance method on
JupiterService), update any call sites to use the instance method, and pass the
instance API key into the queue/retry helpers rather than reading a module-level
variable; also stop starting the queue timers at import—initialize and start
those timers from JupiterService.start() or the constructor so each service
instance controls its own timers and retry behavior.
🧹 Nitpick comments (3)
build.ts (1)

36-54: Remove if (true) constant condition and dead else branch.

The if (true) guard (flagged by Biome's noConstantCondition) makes the type-check-only path on lines 45–54 unreachable dead code. If the alternative path is kept for future toggling, consider using an explicit config flag or environment variable instead.

Proposed cleanup
   const dtsStart = Date.now();
-  if (true) { // Always generate .d.ts
-    console.log("📝 Generating TypeScript declarations...");
-    try {
-      await $`tsc --project tsconfig.build.json`;
-      console.log(`✅ Declarations generated in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
-    } catch (error) {
-      console.warn(`⚠️  TypeScript declaration generation had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
-      console.warn("   Build will continue - fix type errors when possible");
-    }
-  } else {
-    console.log("🔍 Type checking...");
-    try {
-      await $`tsc --noEmit --incremental --project tsconfig.build.json`;
-      console.log(`✅ Type check passed in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
-    } catch (error) {
-      console.warn(`⚠️  Type checking had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
-      console.warn("   Build will continue - fix type errors when possible");
-    }
+  console.log("📝 Generating TypeScript declarations...");
+  try {
+    await $`tsc --project tsconfig.build.json`;
+    console.log(`✅ Declarations generated in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
+  } catch (error) {
+    console.warn(`⚠️  TypeScript declaration generation had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
+    console.warn("   Build will continue - fix type errors when possible");
   }
src/service.ts (2)

312-316: Redundant API headers — applied both here and inside getSwapWithRetry.

getApiHeaders() is called here at line 314 to build the payload, and then again inside getSwapWithRetry (line 119) where it's merged with payload.headers. The duplication is harmless but confusing. Pick one site — either the caller or the retry helper — to own header injection.


76-96: Queue polling starts at module import — before any service is configured.

checkQuoteQueues() (line 96) and checkSwapQueues() (line 172) fire as soon as this module is imported, running setTimeout loops indefinitely even if no JupiterService is ever started. These timers should be started from start() and cleared in stop() to avoid unnecessary work and allow clean shutdown.

Also applies to: 153-172

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Jupiter integration to use api.jup.ag and attach an x-api-key header sourced from runtime settings, and replaces the previous tsup-based build with a Bun-based build script plus a dedicated TS build tsconfig.

Changes:

  • Switch quote/swap requests from lite-api.jup.ag to api.jup.ag and add API-key header support via JUPITER_API_KEY.
  • Add Bun-based build pipeline (build.ts) and tsconfig.build.json for declaration generation.
  • Expand .gitignore to include additional build/cache/artifact patterns.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/service.ts Uses new Jupiter base URL, injects x-api-key header, and adds some type annotations/caching tweaks.
build.ts New Bun build script to bundle ESM output and generate .d.ts via tsc.
tsconfig.build.json New TS config intended for declaration-only emit.
package.json Switches build/dev scripts from tsup to Bun build script.
.gitignore Adds common dependency/build/cache/log ignore patterns.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 4 to 28
async function build() {
const totalStart = Date.now();
const pkg = await Bun.file("package.json").json();
const externalDeps = [
...Object.keys(pkg.dependencies ?? {}),
...Object.keys(pkg.peerDependencies ?? {}),
];

// Use the clean script from package.json
if (pkg.scripts?.clean) {
console.log("🧹 Cleaning...");
await $`bun run clean`.quiet();
}

const esmStart = Date.now();
console.log("🔨 Building @elizaos/plugin-jupiter...");
const esmResult = await Bun.build({
entrypoints: ["src/index.ts"],
outdir: "dist",
target: "node",
format: "esm",
sourcemap: "external",
minify: false,
external: externalDeps,
});
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dev runs bun run build.ts --watch, but build.ts never reads CLI args and doesn’t enable any watch mode for Bun.build. As-is, --watch is ignored and dev mode will just run a single build and exit.

Copilot uses AI. Check for mistakes.
odilitime and others added 5 commits February 11, 2026 01:04
build.ts doesn't implement watch mode; tsup does natively.

Co-authored-by: Cursor <cursoragent@cursor.com>
Both methods were using fabricated public.jupiterapi.com URLs that never
existed. getTokenPair now uses Tokens API V2 Search endpoint with API key
auth. getHistoricalPrices now uses Price API V3 (current prices only, as
Jupiter does not offer a historical price endpoint).

Co-authored-by: Cursor <cursoragent@cursor.com>
api.jup.ag requires an API key for all requests. If none is configured,
log an error and bail out of start() instead of silently failing on
every request.

Co-authored-by: Cursor <cursoragent@cursor.com>
getTokenPrice was dividing outAmount by inputDecimals instead of
outputDecimals — e.g. 1 SOL (9 decimals) to USDC (6 decimals) would
return 0.15 instead of 150. Added outputDecimals param defaulting to 6.

Cache key in getQuote now uses intAmount (the parsed value actually sent
to the API) instead of the raw amount param, preventing mismatches when
a float is passed in.

Co-authored-by: Cursor <cursoragent@cursor.com>
routeCache was an unbounded Record that never evicted entries. Now uses
a Map with 30s TTL and 100-entry FIFO cap. Expired entries are swept on
insert, and oldest entries are evicted when at capacity.

Queue timers (checkQuoteQueues/checkSwapQueues) were starting at import
time even if no service was created or JUPITER_API_KEY was missing. Now
deferred behind startQueues() which is called once from start().

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/service.ts (2)

751-765: ⚠️ Potential issue | 🟠 Major

stop() doesn't cancel queue timers — processing continues after "stop".

checkQuoteQueues and checkSwapQueues schedule themselves with setTimeout indefinitely. stop() only flips isRunning but never breaks the timer chain, so the queues keep draining (or spinning) after the service claims to be stopped. Additionally, queuesStarted is never reset, so a subsequent start() on a new instance won't re-initialize the timers.

Store the timer handles and clear them in stop():

♻️ Sketch
-let queuesStarted = false;
+let queuesStarted = false;
+let quoteTimer: ReturnType<typeof setTimeout> | null = null;
+let swapTimer: ReturnType<typeof setTimeout> | null = null;

 // in checkQuoteQueues:
-  setTimeout(checkQuoteQueues, delayInMs)
+  quoteTimer = setTimeout(checkQuoteQueues, delayInMs)

 // in checkSwapQueues:
-  setTimeout(checkSwapQueues, delayInMs)
+  swapTimer = setTimeout(checkSwapQueues, delayInMs)

+function stopQueues() {
+  if (quoteTimer) clearTimeout(quoteTimer);
+  if (swapTimer) clearTimeout(swapTimer);
+  queuesStarted = false;
+}

 // in stop():
+  stopQueues();
   this.isRunning = false;

711-749: ⚠️ Potential issue | 🟠 Major

Static start() returns a non-running service silently when the API key is missing.

If JUPITER_API_KEY is absent, instance start() logs an error and returns (line 738), but the static start() (line 711-715) still returns the service object to the caller. Downstream code will receive a JupiterService where isRunning === false and no queue timers are active, yet no error is thrown. This makes misconfiguration hard to detect.

Either throw from start() so the caller knows the service failed, or have the static factory propagate the failure:

      if (!apiKey) {
-       logger.error('JUPITER_API_KEY is not set — Jupiter service will not start. Get one at https://portal.jup.ag');
-       return;
+       throw new Error('JUPITER_API_KEY is not set — Jupiter service cannot start. Get one at https://portal.jup.ag');
      }
🧹 Nitpick comments (6)
src/service.ts (6)

224-239: Route cache TTL + eviction looks good; minor lint fix on line 231.

The static analysis tool flags line 231 because the forEach callback implicitly returns the boolean from Map.prototype.delete. While harmless at runtime, it's easy to silence:

♻️ Suggested fix
-    expired.forEach(k => this.routeCache.delete(k));
+    for (const k of expired) this.routeCache.delete(k);

123-129: getApiHeaders() called twice in the swap path — redundant merge.

executeSwap already sets headers: getApiHeaders() in the payload (line 342), and then getSwapWithRetry merges getApiHeaders() again at line 128 before spreading payload.headers on top. The result is correct but getApiHeaders() is invoked twice with identical output.

Pick one site — either let the caller set headers (and don't call getApiHeaders() again inside getSwapWithRetry), or always apply them inside getSwapWithRetry and don't require callers to pass them.


262-266: parseInt(String(amount)) silently truncates fractional values.

amount is typed number. If a caller computes atomic units via floating-point math and passes e.g. 1000000.7, parseInt silently drops the fraction. Math.round (or Math.trunc if truncation is intentional) makes the intent explicit and avoids the unnecessary String() conversion:

-      const intAmount = parseInt(String(amount))
+      const intAmount = Math.round(amount)

78-84: Untyped quote / swap parameters in queue processors.

processQuoteQueue and processSwapQueue accept untyped parameters. A lightweight interface (e.g., { url: string; resolveHandle: (v: unknown) => void; rejectHandle: (r?: any) => void }) would prevent accidental property misspellings and align with the typed enqueue functions.


590-628: getHistoricalPrices doesn't use the timeframe parameter and returns at most 2 current-price entries.

The method signature accepts timeframe but ignores it, and the implementation returns current snapshots, not historical data. The inline comment on lines 587-589 acknowledges this, but callers relying on the name and signature will be misled. Consider renaming to getCurrentPrices or removing the unused timeframe field to avoid confusion.


772-788: Remove unused getCacheExp and setCacheExp functions.

These helper functions are never called anywhere in the codebase and are not exported. They appear to be leftover experimental code (indicated by the "hack these in here" comment). Removing them will reduce confusion and clutter.

Iteration 1

prr-fix:prrc_kwdootnhpm6mw0f0
prr-fix:prrc_kwdootnhpm6mw0my
prr-fix:prrc_kwdootnhpm6mw0nz
prr-fix:prrc_kwdootnhpm6mw0m7
prr-fix:prrc_kwdootnhpm6mw0my
prr-fix:prrc_kwdootnhpm6mw0nt
prr-fix:prrc_kwdootnhpm6mw0ne
prr-fix:prrc_kwdootnhpm6mw0nj
prr-fix:prrc_kwdootnhpm6mw1ez
prr-fix:prrc_kwdootnhpm6mw-ag
prr-fix:prrc_kwdootnhpm6mw-ai
prr-fix:prrc_kwdootnhpm6mw-ak
prr-fix:prrc_kwdootnhpm6mw1ex
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/service.ts (1)

756-769: ⚠️ Potential issue | 🟡 Minor

stop() does not halt the queue polling timers.

checkQuoteQueues and checkSwapQueues use recursive setTimeout that runs indefinitely once startQueues() is called. stop() only flips isRunning but never cancels these timers, so the polling loops continue after the service is "stopped". This also means any items enqueued after stop() will still be processed.

Consider storing the timeout handles and clearing them in stop(), or checking a running flag at the top of each check*Queues function to break the loop.

🤖 Fix all issues with AI agents
In `@build.ts`:
- Around line 37-43: The catch block after the tsc invocation (the await $`tsc
--project tsconfig.build.json` around dtsStart) is currently swallowing errors;
change it to log the actual error/details (include the caught error variable)
and fail the build in CI/strict modes by exiting non‑zero (e.g.,
process.exit(1>) or rethrow) when an env flag like CI or STRICT_BUILD (or a
--strict CLI flag you add) is set; otherwise still warn but print full error
output and include the elapsed time using dtsStart so you can debug
missing/failed .d.ts generation.

In `@src/service.ts`:
- Around line 562-565: getTokenPair and getHistoricalPrices are calling fetch()
directly (the two fetch(...) calls creating inputResponse/outputResponse and the
later historical price fetches), bypassing the app's rate-limiting queue and
risking 429s; change these to use the same queued/throttled request path used
for quotes/swaps (i.e., route the token metadata and historical-price HTTP
requests through the existing queue dispatch/enqueue method instead of calling
fetch() directly), or add a dedicated throttled wrapper that uses the queue for
all requests that hit api.jup.ag so both getTokenPair and getHistoricalPrices
use the centralized rate-limiter.
🧹 Nitpick comments (7)
package.json (2)

17-21: Build/dev script inconsistency: build uses Bun but dev still uses tsup.

The production build (bun run build.ts) and the dev build (tsup --format esm --dts --watch) use entirely different toolchains, which can produce subtly different output (module resolution, tree-shaking, source maps). This makes it easy to miss issues that only appear in the production build.

Consider either:

  • Adding --watch support to build.ts and using it for dev too, or
  • Keeping tsup for both until the migration is complete.

7-9: engines.bun constraint may be too loose and lacks a node engine entry.

"bun": ">=1.0.0" allows any Bun version. Since Bun.build() API has evolved across versions, consider pinning to a narrower range (e.g., ">=1.1.0"). Also, if the package is consumed by Node-based projects (the build targets node), you may want a node engine entry too.

src/service.ts (5)

228-231: Static analysis: forEach callback implicitly returns a value.

Array.push() returns the new length, so the arrow function body implicitly returns a number. While forEach ignores return values, the linter flags this as suspicious. Use a block body or prefix with void.

Proposed fix
-    this.routeCache.forEach((v, k) => {
-      if (now > v.expiry) expired.push(k);
-    });
+    for (const [k, v] of this.routeCache) {
+      if (now > v.expiry) expired.push(k);
+    }

123-129: Headers are constructed twice for swap requests — redundant but worth simplifying.

executeSwap (line 342) already calls getApiHeaders() to build payload.headers. Then getSwapWithRetry calls getApiHeaders() again and merges with payload.headers (line 128). The double call is functionally harmless but adds confusion.

Let getSwapWithRetry own header construction exclusively, and have callers pass only the request body/method — or at least document the merge contract.

Proposed simplification in executeSwap
       const swapData = await swapEnqueue(`${JUPITER_BASE_URL}/swap`, {
         method: 'POST',
-        headers: getApiHeaders(),
         body: JSON.stringify(body),
       })

34-60: Network-level fetch failures (DNS, TCP, TLS) are not retried.

Both getQuoteWithRetry and getSwapWithRetry only retry on HTTP 429 responses. If fetch itself throws (e.g., TypeError for DNS resolution failure, connection reset, or timeout), the error propagates immediately and exhausts no retries. Wrapping the fetch call in a try/catch inside the loop and treating transient network errors as retryable would improve resilience.

Also applies to: 123-151


37-37: Debug console.log statements should use logger or be removed.

Multiple console.log calls are scattered throughout the queue and retry functions (e.g., lines 37, 43, 91, 100, 126, 166, 175). These bypass the structured logger used elsewhere in the service and will produce noisy output in production. Either promote them to logger.debug / logger.info or remove them.

Also applies to: 91-91, 100-100, 126-126, 166-166, 175-175


262-262: Use Math.trunc() instead of parseInt(String(amount)) for clarity and efficiency.

The parseInt(String(amount)) pattern works correctly, but is unnecessarily verbose. Since amount is already a number, Math.trunc(amount) directly truncates the value and is the idiomatic approach in modern JavaScript.

Suggested change
-      const intAmount = parseInt(String(amount))
+      const intAmount = Math.trunc(amount)

Iteration 1

prr-fix:prrc_kwdootnhpm6mw0no
prr-fix:prrc_kwdootnhpm6mw0nq
prr-fix:prrc_kwdootnhpm6nec1l
prr-fix:prrc_kwdootnhpm6nec1n
prr-fix:prrc_kwdootnhpm6neder
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/service.ts`:
- Around line 244-251: The queue timer loops started by startQueues() (which
calls checkQuoteQueues, checkSwapQueues, checkMetadataQueues) never get
cancelled because stop() only flips isRunning and queuesStarted prevents
restart; update the implementation to track the timer IDs (e.g., store them in a
module-level object or array like queueTimerIds) when scheduling setTimeout in
each check*Queue and add a new stopQueues() that clears those timers with
clearTimeout and resets queuesStarted; alternatively (or in addition) make each
check*Queue read a running flag (isRunning or queuesRunning) at the top and stop
rescheduling when false; finally call stopQueues() from stop() to ensure timers
are cancelled and stale chains are broken.
- Line 327: The code uses parseInt(String(amount)) to derive intAmount which is
fragile for large number-typed amount values; replace this expression with an
explicit numeric truncation like Math.trunc(Number(amount)) (or
Math.floor(Number(amount)) if you prefer rounding down) to drop any fractional
atomic units safely; update the assignment to intAmount and remove
parseInt(String(amount)) references so amount (the number parameter) is
converted via Number(...) and truncated with Math.trunc to avoid
scientific-notation parsing issues.
🧹 Nitpick comments (4)
src/service.ts (4)

405-409: Redundant double-application of API headers in executeSwap.

getApiHeaders(this.apiKey) is set in the payload at line 407, and then this.apiKey is also passed as the third argument to swapEnqueue. Inside getSwapWithRetry (line 127), headers are rebuilt from the apiKey param and merged with payload.headers — so the same headers are computed and spread twice.

Pick one path: either pass headers in the payload or rely on the apiKey parameter. The current duplication will silently mask bugs if the two diverge.

Suggested: drop headers from payload, let getSwapWithRetry handle it
       const swapData = await swapEnqueue(`${JUPITER_BASE_URL}/swap`, {
         method: 'POST',
-        headers: getApiHeaders(this.apiKey),
         body: JSON.stringify(body),
       }, this.apiKey)

293-296: Arrow function in forEach implicitly returns the result of Map.delete().

Static analysis flags this as useIterableCallbackReturn. Trivial fix: add braces or use a for...of loop.

Fix
-    expired.forEach(k => this.routeCache.delete(k));
+    for (const k of expired) this.routeCache.delete(k);

32-34: Scattered console.log debug statements — use logger consistently.

The module imports logger from @elizaos/core but the queue/retry functions use raw console.log for debug output (lines 34, 40, 89, 98, 125, 133, 174, 203, 231, 238). These should use logger.debug or logger.info for consistent log levels and structured output, and the commented-out console.log lines (32, 50, etc.) should be removed.

Also applies to: 40-40, 89-89, 98-98


648-684: getHistoricalPrices returns current snapshots — consider renaming.

The method name and return type (Array<{ timestamp: number; price: number }>) suggest time-series data, but it returns at most two current-price entries. The inline comments acknowledge this, but callers will find the API misleading. Consider renaming to getCurrentPrices or getPriceSnapshot to match the actual behavior. If the historical signature must be preserved for backward compatibility, a @deprecated JSDoc pointing to the new name would help.

Iteration 1

prr-fix:prrc_kwdootnhpm6nec1p
prr-fix:prrc_kwdootnhpm6neg29
prr-fix:prrc_kwdootnhpm6neg2-
timestamp: now,
price: Number(tokenData.usdPrice),
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zero-priced tokens are silently dropped

Low Severity

getCurrentPrices() uses if (tokenData?.usdPrice), which treats 0 as missing. Tokens with an actual usdPrice of 0 are omitted from results, producing incomplete price snapshots.

Fix in Cursor Fix in Web

Iteration 3

prr-fix:prrc_kwdootnhpm6mw0my
prr-fix:prrc_kwdootnhpm6mw1ex
prr-fix:prrc_kwdootnhpm6nec1n
prr-fix:prrc_kwdootnhpm6neipk
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/service.ts`:
- Around line 659-692: getCurrentPrices currently returns Array<{
timestamp:number; price:number }> with no mint identifier, breaking mapping when
one token is missing; modify the function (getCurrentPrices) to include the mint
address in each returned entry (e.g. { mint: string; timestamp: number; price:
number }) and update the method's return type accordingly, ensure the loop that
builds prices uses the loop variable mint to set the mint field and still only
includes entries when usdPrice is defined, and adjust any callers or type
annotations that expect the old shape.
- Around line 245-258: stopQueues() currently clears timers but leaves pending
items in the quotes, swaps, and metadata queues whose promises never settle;
modify stopQueues to iterate each queue (quotes, swaps, metadata), for each
queued item call its rejectHandle (or resolveHandle if you prefer resolve) with
a clear Error explaining the queue was stopped, then clear those arrays and
clear the corresponding timers (queueTimers.quotes, queueTimers.swaps,
queueTimers.metadata) before setting queuesStarted = false; reference the
stopQueues function and the queued-item fields resolveHandle/rejectHandle to
implement the drain-and-reject behavior so callers don't hang.

In `@test_fail.ts`:
- Around line 3-11: The test currently treats the thrown error as failure;
invert the exit logic in async function main so the expected path (await $`bun
run non_existent_command` throws) results in process.exit(0) and the unexpected
path (no throw) results in process.exit(1). Update the try/catch around the
awaited command in main: on success (no exception) log the unexpected outcome
and call process.exit(1), and in the catch block log the expected outcome and
call process.exit(0).
🧹 Nitpick comments (5)
src/service.ts (5)

297-312: Static analysis: forEach callback implicitly returns the boolean from Map.delete().

Line 304's arrow function k => this.routeCache.delete(k) returns the boolean result of delete(). While harmless at runtime, it triggers the Biome lint rule useIterableCallbackReturn. Use a block body to suppress the implicit return.

Proposed fix
-    expired.forEach(k => this.routeCache.delete(k));
+    expired.forEach(k => { this.routeCache.delete(k); });

413-417: Headers are applied twice for swap requests.

executeSwap constructs the payload with headers: getApiHeaders(this.apiKey) (line 415) and also passes this.apiKey as the third argument to swapEnqueue (line 417). Inside getSwapWithRetry (line 128-129), the API headers are merged again via { ...getApiHeaders(apiKey), ...payload.headers }. The result is correct (same key both times) but redundant — either pass headers in the payload or via apiKey, not both.

Proposed fix — let getSwapWithRetry own the headers
       const swapData = await swapEnqueue(`${JUPITER_BASE_URL}/swap`, {
         method: 'POST',
-        headers: getApiHeaders(this.apiKey),
         body: JSON.stringify(body),
       }, this.apiKey)

7-7: Queue items and enqueue functions are entirely untyped.

The three queues use any[] and the process*Queue functions accept untyped parameters. Introducing a simple interface per queue item would catch mismatches at compile time and improve IDE support.

Example interface sketch
interface QueueItem<T = unknown> {
  url: string;
  apiKey: string | null;
  resolveHandle: (value: T) => void;
  rejectHandle: (reason?: unknown) => void;
}

interface SwapQueueItem extends QueueItem {
  payload: RequestInit;
}

Also applies to: 61-74, 106-121, 182-196


636-639: Promise.all with two metadata-queue items serialises to ~2 s minimum.

Both metadataEnqueue calls enter the same 1 RPS queue, so they execute sequentially despite the Promise.all. This is technically correct for rate limiting, but if latency matters for getTokenPair, consider batching both mints into a single request (if the API supports it) or documenting the expected delay.


32-58: Retry loops lack a jitter component, risking thundering-herd on shared queues.

Both getQuoteWithRetry and getMetadataWithRetry (and getSwapWithRetry) use pure exponential backoff (delay *= 2) on 429s. When multiple items are queued and all hit 429 simultaneously, they'll all retry at the same wall-clock intervals. Adding a small random jitter (e.g., delay *= 2; delay += Math.random() * 500;) would spread retries out.

Also applies to: 198-218

Comment on lines 659 to 692
async getCurrentPrices({
inputMint,
outputMint,
timeframe = '24h', // Options: 1h, 24h, 7d, 30d
}: {
inputMint: string;
outputMint: string;
timeframe?: string;
}): Promise<Array<{ timestamp: number; price: number }>> {
try {
// Fetch historical price data from Jupiter API
const response = await fetch(
`https://public.jupiterapi.com/v1/prices/${inputMint}/${outputMint}?timeframe=${timeframe}`
// Routed through metadata queue to respect rate limits
const result: any = await metadataEnqueue(
`https://api.jup.ag/price/v3?ids=${inputMint},${outputMint}`,
this.apiKey
);

if (!response.ok) {
throw new Error('Failed to fetch historical prices');
const prices: Array<{ timestamp: number; price: number }> = [];
const now = Date.now();

for (const mint of [inputMint, outputMint]) {
const tokenData = result[mint];
// Check for defined price, allowing 0
if (tokenData && tokenData.usdPrice !== undefined && tokenData.usdPrice !== null) {
prices.push({
timestamp: now,
price: Number(tokenData.usdPrice),
});
}
}

return await response.json();
return prices;
} catch (error) {
logger.error('Failed to get historical prices:', error);
logger.error('Failed to get prices:', error);
throw error;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

getCurrentPrices return type doesn't identify which token each price belongs to.

The method returns Array<{ timestamp: number; price: number }> with up to two entries, but there's no way for the caller to know which element corresponds to inputMint vs outputMint. If one token has no price data, the array shrinks and the positional mapping breaks. Consider including the mint address in each entry.

Proposed adjustment
-  const prices: Array<{ timestamp: number; price: number }> = [];
+  const prices: Array<{ mint: string; timestamp: number; price: number }> = [];
   ...
         prices.push({
+          mint,
           timestamp: now,
           price: Number(tokenData.usdPrice),
         });

Also note: the return type signature still says Array<{ timestamp: number; price: number }> — update the method signature to match if you add the mint field.

🤖 Prompt for AI Agents
In `@src/service.ts` around lines 659 - 692, getCurrentPrices currently returns
Array<{ timestamp:number; price:number }> with no mint identifier, breaking
mapping when one token is missing; modify the function (getCurrentPrices) to
include the mint address in each returned entry (e.g. { mint: string; timestamp:
number; price: number }) and update the method's return type accordingly, ensure
the loop that builds prices uses the loop variable mint to set the mint field
and still only includes entries when usdPrice is defined, and adjust any callers
or type annotations that expect the old shape.

Iteration 1

prr-fix:prrc_kwdootnhpm6mw1ex
prr-fix:prrc_kwdootnhpm6nedeq
prr-fix:prrc_kwdootnhpm6nfiha
prr-fix:prrc_kwdootnhpm6nfijz
prr-fix:prrc_kwdootnhpm6nfij1
outputMint: string;
timeframe?: string;
}): Promise<Array<{ timestamp: number; price: number }>> {
}): Promise<Array<{ mint: string; timestamp: number; price: number }>> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Public price API contract was broken

Medium Severity

The commit removes getHistoricalPrices and replaces it with getCurrentPrices with a different request/response contract. Existing consumers calling getHistoricalPrices or relying on timeframe and historical point output will break because there is no compatibility method or adapter in src/service.ts.

Additional Locations (1)

Fix in Cursor Fix in Web

Iteration 3

prr-fix:prrc_kwdootnhpm6mw-ag
prr-fix:prrc_kwdootnhpm6neg2-
prr-fix:prrc_kwdootnhpm6mw0nd
prr-fix:prrc_kwdootnhpm6neiph
prr-fix:prrc_kwdootnhpm6neipi
prr-fix:prrc_kwdootnhpm6nfig9
prr-fix:prrc_kwdootnhpm6nfijx
User1 added 2 commits February 15, 2026 18:03
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
Explains reasoning for dismissed issues inline in code
User1 added 2 commits February 16, 2026 01:34
Iteration 1

prr-fix:prrc_kwdootnhpm6mw0my
prr-fix:prrc_kwdootnhpm6mw1ex
prr-fix:prrc_kwdootnhpm6nfijz
prr-fix:prrc_kwdootnhpm6ngqp2
prr-fix:prrc_kwdootnhpm6ngxtt
Explains reasoning for dismissed issues inline in code
metadataEnqueue(
this.queueState,
`https://api.jup.ag/markets/v1?baseMint=${inputMint}&quoteMint=${outputMint}`,
this.getApiHeaders()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsupported markets endpoint breaks pair lookup

Medium Severity

getTokenPair now calls https://api.jup.ag/markets/v1 through metadataEnqueue, but this path is not part of Jupiter’s documented API. When that request returns non-2xx, Promise.all rejects and getTokenPair throws, so pair metadata cannot be returned even when token searches succeed.

Fix in Cursor Fix in Web

User1 and others added 6 commits February 16, 2026 02:26
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
Iteration 1

prr-fix:prrc_kwdootnhpm6ngvcq
prr-fix:prrc_kwdootnhpm6nla7u
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
results[0].status === 'fulfilled' ? results[0].value : [],
results[1].status === 'fulfilled' ? results[1].value : [],
results[2].status === 'fulfilled' ? results[2].value : null,
]) as [any[], any[], any];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token pair silently hides API failures

Medium Severity

getTokenPair uses Promise.allSettled and converts rejected metadataEnqueue calls into empty defaults, then returns combinedTokenLiquidity/combinedTokenVolume24h as 0 or tokens as null. API/auth/network failures are therefore reported as valid low-data results instead of surfacing an error.

Additional Locations (1)

Fix in Cursor Fix in Web

src/service.ts Outdated
liquidity: number;
volume24h: number;
combinedTokenLiquidity: number;
combinedTokenVolume24h: number;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token pair response keys unexpectedly renamed

Medium Severity

getTokenPair changed its output contract from liquidity/volume24h to combinedTokenLiquidity/combinedTokenVolume24h. Existing consumers reading the prior fields now receive undefined without an exception, causing silent downstream logic errors after upgrading.

Additional Locations (1)

Fix in Cursor Fix in Web

src/service.ts Outdated
[mint: string]: {
prices: Array<{ timestamp: number; price: number }>;
};
}> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Historical prices return shape was broken

Medium Severity

getHistoricalPrices changed from returning an array of {timestamp, price} points to returning an object keyed by mint with nested prices. Callers using the previous array contract now mis-handle successful responses, which breaks existing parsing and time-series workflows.

Additional Locations (1)

Fix in Cursor Fix in Web

Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
- service.ts: ### Token pair silently hides API failures

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Token pair response keys unexpectedly renamed

**Medium Severity**

<!-- ...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
- service.ts: ### Token pair silently hides API failures

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Token pair response keys unexpectedly renamed

**Medium Severity**

<!-- ...
results[0].status === 'fulfilled' ? results[0].value : [],
results[1].status === 'fulfilled' ? results[1].value : [],
results[2].status === 'fulfilled' ? results[2].value : null,
]) as [any[], any[], any];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token pair silently masks API failures

Medium Severity

getTokenPair uses Promise.allSettled and replaces rejected metadataEnqueue calls with empty values, so API/auth/rate-limit failures look like successful responses. The method can return null tokens and zero liquidity/volume instead of surfacing an error from src/service.ts.

Fix in Cursor Fix in Web

Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
- service.ts: ### Token pair silently hides API failures

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Token pair response keys unexpectedly renamed

**Medium Severity**

<!-- ...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
- service.ts: ### Token pair silently hides API failures

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Token pair response keys unexpectedly renamed

**Medium Severity**

<!-- ...
results[0].status === 'fulfilled' ? results[0].value : [],
results[1].status === 'fulfilled' ? results[1].value : [],
results[2].status === 'fulfilled' ? results[2].value : null,
]) as [any[], any[], any];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token pair failures are silently masked

Medium Severity

getTokenPair uses Promise.allSettled and replaces rejected API calls with empty values, so upstream failures become a successful response with null tokens and 0 liquidity/volume. This hides real data-fetch errors from callers and can make downstream trading logic treat missing data as valid market data.

Additional Locations (1)

Fix in Cursor Fix in Web

checkQuoteQueues(queueState);
checkSwapQueues(queueState);
checkMetadataQueues(queueState);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three independent queues exceed combined API rate limit

Medium Severity

The three queue processing loops (checkQuoteQueues, checkSwapQueues, checkMetadataQueues) each independently enforce a 1-second interval via setTimeout, but they run concurrently against the same API key. The comments explicitly note "1 RPS basic tier" yet startQueues kicks off all three loops simultaneously, meaning up to 3 requests per second can hit api.jup.ag. This is especially likely during getTokenPair calls (which enqueue 3 metadata items) overlapping with quote requests, causing unnecessary 429 errors and increased latency from exponential backoff retries.

Additional Locations (2)

Fix in Cursor Fix in Web

if (!queueState.started) return;
// 1 RPS basic tier; queue throttles to be respectful
queueState.timers.metadata = setTimeout(() => checkMetadataQueues(queueState), delayInMs)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metadata queue functions duplicate quote queue code

Low Severity

The entire metadata queue implementation (metadataEnqueue, getMetadataWithRetry, processMetadataQueue, checkMetadataQueues) is a near-identical copy of the quote queue functions (quoteEnqueue, getQuoteWithRetry, processQuoteQueue, checkQuoteQueues). Both handle GET-with-headers requests using the same retry/backoff logic, only differing in log message text and the sub-queue they target. This ~75 lines of duplicated logic increases maintenance burden — a bug fix in the retry logic would need to be applied in three places.

Fix in Cursor Fix in Web

test_fail.ts Outdated
@@ -0,0 +1 @@

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty test file accidentally committed

Low Severity

test_fail.ts contains only a blank line. The PR summary describes it as "a test demonstrating failure handling for missing commands," but the file has no actual test code. This appears to be an accidental commit of a placeholder file.

Fix in Cursor Fix in Web

Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
- service.ts: ### Token pair silently hides API failures

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Token pair response keys unexpectedly renamed

**Medium Severity**

<!-- ...
- service.ts: ### Token pair failures are silently masked

**Medium Severity**

<!-- DESCRI...
src/service.ts Outdated
// Re-check after async work in case stop() was called during processing
if (!queueState.started) return;
// 1 RPS basic tier; queue throttles to be respectful
queueState.timers.metadata = setTimeout(() => checkMetadataQueues(queueState), delayInMs)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metadata queue infrastructure duplicates quote queue logic

Medium Severity

The four new metadata queue functions (metadataEnqueue, getMetadataWithRetry, processMetadataQueue, checkMetadataQueues) are near-verbatim copies of their quote queue counterparts (quoteEnqueue, getQuoteWithRetry, processQuoteQueue, checkQuoteQueues). Both metadataEnqueue and quoteEnqueue take identical parameters and have identical logic — only the target queue array differs. Likewise, getMetadataWithRetry and getQuoteWithRetry share the same retry/backoff/fetch logic with only the log prefix changed. This ~75 lines of duplication means any bug fix (e.g., in retry logic or error handling) needs to be applied in three places, increasing the risk of inconsistent fixes.

Additional Locations (1)

Fix in Cursor Fix in Web

test_fail.ts Outdated
@@ -0,0 +1 @@

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty test file accidentally committed to repository

Low Severity

test_fail.ts is a completely empty file (only a blank line). The PR summary describes it as "a test demonstrating failure handling for missing commands," but it contains no test code. This appears to be an accidental commit of a placeholder that was never filled in.

Fix in Cursor Fix in Web

Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: Dead code - `if (true)` branch will always execute, the `else` block on line ...
- package.json: _⚠️ Potential issue_ | _🟡 Minor_

**`--watch` flag is silently ignored; `tsu...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: If `JUPITER_API_KEY` is missing, start() only logs a warning and continues, b...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- tsconfig.build.json: tsconfig.build.json is not valid JSON due to a trailing comma after the "lib"...
- tsconfig.build.json: tsconfig.build.json overrides `lib` to `["ESNext"]`, which drops the base con...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- service.ts: The API key is stored in a module-level variable (`jupiterApiKey`) and used b...
- service.ts: Unused function getCacheExp.
- service.ts: Unused function setCacheExp.
- service.ts: ### API key not reset when service starts without key

**Low Severity**

<!--...
- build.ts: ### Dead else branch due to `if (true)` conditional

**Low Severity**

<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored

**Medium Severity**

<!-- ...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: ### Price parsing uses non-existent fields

**Medium Severity**

<!-- DESCRIP...
- build.ts: ### Build succeeds after declaration failures

**Medium Severity**

<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_

**Silently continuing after declaration ge...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Historical prices now return current snapshot

**Medium Severity**

<!-- ...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Zero-priced tokens are silently dropped

**Low Severity**

<!-- DESCRIPTI...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- test_fail.ts: ### Debug failure script committed to repository

**Low Severity**

<!-- DESC...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`getCurrentPrices` return type doesn't i...
- test_fail.ts: _⚠️ Potential issue_ | _🟡 Minor_

**Test logic is inverted — exits with fail...
- service.ts: ### Public price API contract was broken

**Medium Severity**

<!-- DESCRIPTI...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Historical price API contract removed

**Medium Severity**

<!-- DESCRIPT...
- service.ts: ### Service starts without required API key

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- test_fail.ts: ### Empty test file committed instead of deletion

**Low Severity**

<!-- DES...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Unsupported markets endpoint breaks pair lookup

**Medium Severity**

<!-...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
- service.ts: ### Token pair silently hides API failures

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Token pair response keys unexpectedly renamed

**Medium Severity**

<!-- ...
- service.ts: ### Token pair failures are silently masked

**Medium Severity**

<!-- DESCRI...
- service.ts: ### Three independent queues exceed combined API rate limit

**Medium Severit...
- test_fail.ts: ### Empty test file accidentally committed

**Low Severity**

<!-- DESCRIPTIO...
results[0].status === 'fulfilled' ? results[0].value : [],
results[1].status === 'fulfilled' ? results[1].value : [],
results[2].status === 'fulfilled' ? results[2].value : null,
]) as [any[], any[], any];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sequential metadata queue makes getTokenPair very slow

Medium Severity

getTokenPair enqueues three metadataEnqueue calls wrapped in Promise.allSettled, suggesting parallel execution intent. However, all three go into the same sequential metadata queue that processes one item per second. This means every getTokenPair call blocks for a minimum of ~3 seconds, a significant regression from the old single-fetch implementation. The old code did one fetch to public.jupiterapi.com/v1/pairs/... and returned instantly; the new code serializes three requests through a 1 RPS queue.

Additional Locations (1)

Fix in Cursor Fix in Web

if (!queueState.started) return;
// 1 RPS basic tier; queue throttles to be respectful
queueState.timers.metadata = setTimeout(() => checkMetadataQueues(queueState), delayInMs)
// Review: metadata and quote queues are structured differently due to distinct processing requirements.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR review tool comments left in production code

Low Severity

Over a dozen // Review: and // REVIEW: comments are scattered throughout the file. These are auto-generated annotations from the prr review tool — they reference specific line numbers, commit hashes (e.g., b340047), and internal review decisions. They will become stale and misleading as the code evolves, and are not intended as permanent documentation.

Additional Locations (2)

Fix in Cursor Fix in Web

test_fail.ts Outdated
@@ -0,0 +1 @@

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty test file accidentally committed to repository

Low Severity

test_fail.ts contains only a blank line with no actual test code. The PR summary mentions "a test demonstrating failure handling for missing commands" but the file is empty, suggesting it was committed as a placeholder or by mistake.

Fix in Cursor Fix in Web

Iteration 1

prr-fix:prrc_kwdootnhpm6nfig9
prr-fix:prrc_kwdootnhpm6mw-ag
prr-fix:prrc_kwdootnhpm6mw-ai
prr-fix:prrc_kwdootnhpm6mw-ak
prr-fix:prrc_kwdootnhpm6nec1l
prr-fix:prrc_kwdootnhpm6neiph
prr-fix:prrc_kwdootnhpm6neipi
prr-fix:prrc_kwdootnhpm6nf5rl
prr-fix:prrc_kwdootnhpm6ngqp2
prr-fix:prrc_kwdootnhpm6ngbhr
prr-fix:prrc_kwdootnhpm6ngbht
prr-fix:prrc_kwdootnhpm6ngvcq
prr-fix:prrc_kwdootnhpm6nla7u
prr-fix:prrc_kwdootnhpm6n-mbg
prr-fix:prrc_kwdootnhpm6neg29
prr-fix:prrc_kwdootnhpm6ngqp5
prr-fix:prrc_kwdootnhpm6nfiha
prr-fix:prrc_kwdootnhpm6ngpvu
prr-fix:prrc_kwdootnhpm6oavuv
prr-fix:prrc_kwdootnhpm6oavur
prr-fix:prrc_kwdootnhpm6oas3t
prr-fix:prrc_kwdootnhpm6ngxtt
Iteration 3

prr-fix:prrc_kwdootnhpm6n_86m
prr-fix:prrc_kwdootnhpm6nfijx
prr-fix:prrc_kwdootnhpm6mw0no
prr-fix:prrc_kwdootnhpm6mw0nq
prr-fix:prrc_kwdootnhpm6neder
prr-fix:prrc_kwdootnhpm6neg2-
delayInMs -= took
if (delayInMs < 0) delayInMs = 0
console.log('swap took', took.toLocaleString() + 'ms', 'delay now', delayInMs)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three queue checker functions are unreachable dead code

Medium Severity

checkQuoteQueues, checkSwapQueues, and checkMetadataQueues (~130 lines total) are never invoked. startQueues only calls the unified checkQueues function, which handles all three queue types via dequeueNextItem. These three functions only reference themselves recursively and are completely dead code. They share the inFlight and nextRequestAt state with the active checkQueues, so if they were ever accidentally called, they'd corrupt the rate-limiting logic.

Additional Locations (2)

Fix in Cursor Fix in Web

// Fetch token pair information from Jupiter API
const response = await fetch(
`https://public.jupiterapi.com/v1/pairs/${inputMint}/${outputMint}`
// Review: Correctly accesses result[mint].usdPrice at top level per Jupiter Price V3 API structure
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR review tool comments committed as code

Low Severity

At least 10 // Review: and // REVIEW: comments are scattered throughout the file — artifacts from the prr review tool. They reference specific commit hashes (e.g., "addressed in commit b340047"), internal line numbers ("line 676, 684"), and review-response justifications rather than serving as meaningful code documentation. These clutter the codebase and are misleading as permanent comments.

Additional Locations (2)

Fix in Cursor Fix in Web

Changes:
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Module-level `jupiterApiKey` is shared a...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`routeCache` grows without bound — poten...
- service.ts: ### Route cache key omits slippageBps causing stale results

**Medium Severit...
- service.ts: ### Token search with concatenated mints returns no results

**High Severity*...
- service.ts: ### Missing API key silently deadlocks all queued requests

**High Severity**...
- service.ts: ### Token search matches wrong field

**Medium Severity**

<!-- DESCRIPTION S...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Token and price fetches bypass the rate-...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**Queue timers are never cancelled on `sto...
- service.ts: _⚠️ Potential issue_ | _🟡 Minor_

**`parseInt(String(amount))` is fragile fo...
- service.ts: ### Global queue shutdown breaks active instances

**Medium Severity**

<!-- ...
- service.ts: ### Queue workers restart after service stop

**Medium Severity**

<!-- DESCR...
- service.ts: ### Queue timers can restart after service stop

**Medium Severity**

<!-- DE...
- service.ts: _⚠️ Potential issue_ | _🟠 Major_

**`stopQueues()` leaves enqueued items wit...
- service.ts: ### Stop leaves queued requests unresolved

**Medium Severity**

<!-- DESCRIP...
- service.ts: ### Rate limiting no longer global

**Medium Severity**

<!-- DESCRIPTION STA...
- service.ts: ### Requests can hang when service is stopped

**Medium Severity**

<!-- DESC...
- service.ts: ### Token pair metrics are no longer pair-specific

**Medium Severity**

<!--...
- service.ts: ### Historical price endpoint no longer supported

**Medium Severity**

<!-- ...
- service.ts: ### Token volume field parsed incorrectly

**Low Severity**

<!-- DESCRIPTION...
- service.ts: ### Historical price endpoint path is invalid

**Medium Severity**

<!-- DESC...
- service.ts: ### Historical price path is not valid

**Medium Severity**

<!-- DESCRIPTION...
- service.ts: ### Token pair response keys unexpectedly renamed

**Medium Severity**

<!-- ...
- service.ts: ### Historical prices return shape was broken

**Medium Severity**

<!-- DESC...
- service.ts: ### Three independent queues exceed combined API rate limit

**Medium Severit...
- service.ts: ### Metadata queue infrastructure duplicates quote queue logic

**Medium Seve...
- service.ts: ### PR review tool comments left in production code

**Low Severity**

<!-- D...
Iteration 2

prr-fix:prrc_kwdootnhpm6nf5ri
prr-fix:prrc_kwdootnhpm6oyyin
prr-fix:prrc_kwdootnhpm6mw1ex
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

delayInMs -= took
if (delayInMs < 0) delayInMs = 0
console.log('swap took', took.toLocaleString() + 'ms', 'delay now', delayInMs)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead per-queue processor functions never called

Medium Severity

checkQuoteQueues, checkSwapQueues, and checkMetadataQueues (~90 lines total) are fully implemented but never called from any entry point. startQueues only invokes the unified checkQueues function. These dead functions also read and write the same shared mutable state (inFlight, nextRequestAt, timers) as the active checkQueues, creating a fragile situation where accidentally re-enabling any of them would cause conflicting concurrent queue processing and rate-limit violations.

Additional Locations (2)

Fix in Cursor Fix in Web

// Fetch token pair information from Jupiter API
const response = await fetch(
`https://public.jupiterapi.com/v1/pairs/${inputMint}/${outputMint}`
// Review: Correctly accesses result[mint].usdPrice at top level per Jupiter Price V3 API structure
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review comments left in production code

Low Severity

Around 12 // Review: and // REVIEW: comments are scattered throughout service.ts — artifacts from the prr automated review tool. They reference stale line numbers (e.g., "line 676, 684"), commit hashes ("commit b340047"), and internal review-process language. These are not documentation and will mislead future readers as the code evolves.

Additional Locations (2)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments