Conversation
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>
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a Bun-based build orchestrator and tsconfig.build.json, expands .gitignore rules, introduces a Bun-oriented test file, adds PR-review lessons, and refactors 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
Additional Comments (2)
|
There was a problem hiding this comment.
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 | 🔴 CriticalBug:
outAmountis divided by input decimals instead of output decimals.
outAmountis denominated in the output token's atomic units (USDC with 6 decimals by default), but line 369 divides by10 ** 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, but150_000_000 / 10^9 = 0.15instead of the correct150_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 | 🟡 MinorCache key uses raw
amountbut the API receivesintAmount— key mismatch possible.Line 218 parses
amountto an integer (intAmount), but line 224 builds the cache key using the originalamount. Ifamountis 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: Removeif (true)constant condition and deadelsebranch.The
if (true)guard (flagged by Biome'snoConstantCondition) 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 insidegetSwapWithRetry.
getApiHeaders()is called here at line 314 to build the payload, and then again insidegetSwapWithRetry(line 119) where it's merged withpayload.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) andcheckSwapQueues()(line 172) fire as soon as this module is imported, runningsetTimeoutloops indefinitely even if noJupiterServiceis ever started. These timers should be started fromstart()and cleared instop()to avoid unnecessary work and allow clean shutdown.Also applies to: 153-172
There was a problem hiding this comment.
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.agtoapi.jup.agand add API-key header support viaJUPITER_API_KEY. - Add Bun-based build pipeline (
build.ts) andtsconfig.build.jsonfor declaration generation. - Expand
.gitignoreto 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.
build.ts
Outdated
| 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, | ||
| }); |
There was a problem hiding this comment.
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.
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>
There was a problem hiding this comment.
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".
checkQuoteQueuesandcheckSwapQueuesschedule themselves withsetTimeoutindefinitely.stop()only flipsisRunningbut never breaks the timer chain, so the queues keep draining (or spinning) after the service claims to be stopped. Additionally,queuesStartedis never reset, so a subsequentstart()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 | 🟠 MajorStatic
start()returns a non-running service silently when the API key is missing.If
JUPITER_API_KEYis absent, instancestart()logs an error and returns (line 738), but the staticstart()(line 711-715) still returns the service object to the caller. Downstream code will receive aJupiterServicewhereisRunning === falseand 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
forEachcallback implicitly returns the boolean fromMap.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.
executeSwapalready setsheaders: getApiHeaders()in the payload (line 342), and thengetSwapWithRetrymergesgetApiHeaders()again at line 128 before spreadingpayload.headerson top. The result is correct butgetApiHeaders()is invoked twice with identical output.Pick one site — either let the caller set headers (and don't call
getApiHeaders()again insidegetSwapWithRetry), or always apply them insidegetSwapWithRetryand don't require callers to pass them.
262-266:parseInt(String(amount))silently truncates fractional values.
amountis typednumber. If a caller computes atomic units via floating-point math and passes e.g.1000000.7,parseIntsilently drops the fraction.Math.round(orMath.truncif truncation is intentional) makes the intent explicit and avoids the unnecessaryString()conversion:- const intAmount = parseInt(String(amount)) + const intAmount = Math.round(amount)
78-84: Untypedquote/swapparameters in queue processors.
processQuoteQueueandprocessSwapQueueaccept 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:getHistoricalPricesdoesn't use thetimeframeparameter and returns at most 2 current-price entries.The method signature accepts
timeframebut 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 togetCurrentPricesor removing the unusedtimeframefield to avoid confusion.
772-788: Remove unusedgetCacheExpandsetCacheExpfunctions.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
There was a problem hiding this comment.
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.
checkQuoteQueuesandcheckSwapQueuesuse recursivesetTimeoutthat runs indefinitely oncestartQueues()is called.stop()only flipsisRunningbut never cancels these timers, so the polling loops continue after the service is "stopped". This also means any items enqueued afterstop()will still be processed.Consider storing the timeout handles and clearing them in
stop(), or checking a running flag at the top of eachcheck*Queuesfunction 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:builduses Bun butdevstill 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
--watchsupport tobuild.tsand using it fordevtoo, or- Keeping tsup for both until the migration is complete.
7-9:engines.bunconstraint may be too loose and lacks anodeengine entry.
"bun": ">=1.0.0"allows any Bun version. SinceBun.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 targetsnode), you may want anodeengine entry too.src/service.ts (5)
228-231: Static analysis:forEachcallback implicitly returns a value.
Array.push()returns the new length, so the arrow function body implicitly returns a number. WhileforEachignores return values, the linter flags this as suspicious. Use a block body or prefix withvoid.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 callsgetApiHeaders()to buildpayload.headers. ThengetSwapWithRetrycallsgetApiHeaders()again and merges withpayload.headers(line 128). The double call is functionally harmless but adds confusion.Let
getSwapWithRetryown 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-levelfetchfailures (DNS, TCP, TLS) are not retried.Both
getQuoteWithRetryandgetSwapWithRetryonly retry on HTTP 429 responses. Iffetchitself throws (e.g.,TypeErrorfor DNS resolution failure, connection reset, or timeout), the error propagates immediately and exhausts no retries. Wrapping thefetchcall in a try/catch inside the loop and treating transient network errors as retryable would improve resilience.Also applies to: 123-151
37-37: Debugconsole.logstatements should useloggeror be removed.Multiple
console.logcalls are scattered throughout the queue and retry functions (e.g., lines 37, 43, 91, 100, 126, 166, 175). These bypass the structuredloggerused elsewhere in the service and will produce noisy output in production. Either promote them tologger.debug/logger.infoor remove them.Also applies to: 91-91, 100-100, 126-126, 166-166, 175-175
262-262: UseMath.trunc()instead ofparseInt(String(amount))for clarity and efficiency.The
parseInt(String(amount))pattern works correctly, but is unnecessarily verbose. Sinceamountis 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
There was a problem hiding this comment.
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 inexecuteSwap.
getApiHeaders(this.apiKey)is set in the payload at line 407, and thenthis.apiKeyis also passed as the third argument toswapEnqueue. InsidegetSwapWithRetry(line 127), headers are rebuilt from theapiKeyparam and merged withpayload.headers— so the same headers are computed and spread twice.Pick one path: either pass headers in the payload or rely on the
apiKeyparameter. 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 inforEachimplicitly returns the result ofMap.delete().Static analysis flags this as
useIterableCallbackReturn. Trivial fix: add braces or use afor...ofloop.Fix
- expired.forEach(k => this.routeCache.delete(k)); + for (const k of expired) this.routeCache.delete(k);
32-34: Scatteredconsole.logdebug statements — useloggerconsistently.The module imports
loggerfrom@elizaos/corebut the queue/retry functions use rawconsole.logfor debug output (lines 34, 40, 89, 98, 125, 133, 174, 203, 231, 238). These should uselogger.debugorlogger.infofor consistent log levels and structured output, and the commented-outconsole.loglines (32, 50, etc.) should be removed.Also applies to: 40-40, 89-89, 98-98
648-684:getHistoricalPricesreturns 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 togetCurrentPricesorgetPriceSnapshotto match the actual behavior. If the historical signature must be preserved for backward compatibility, a@deprecatedJSDoc pointing to the new name would help.
Iteration 1 prr-fix:prrc_kwdootnhpm6nec1p prr-fix:prrc_kwdootnhpm6neg29 prr-fix:prrc_kwdootnhpm6neg2-
Iteration 3 prr-fix:prrc_kwdootnhpm6mw0my prr-fix:prrc_kwdootnhpm6mw1ex prr-fix:prrc_kwdootnhpm6nec1n prr-fix:prrc_kwdootnhpm6neipk
There was a problem hiding this comment.
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:forEachcallback implicitly returns the boolean fromMap.delete().Line 304's arrow function
k => this.routeCache.delete(k)returns the boolean result ofdelete(). While harmless at runtime, it triggers the Biome lint ruleuseIterableCallbackReturn. 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.
executeSwapconstructs the payload withheaders: getApiHeaders(this.apiKey)(line 415) and also passesthis.apiKeyas the third argument toswapEnqueue(line 417). InsidegetSwapWithRetry(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 viaapiKey, 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 theprocess*Queuefunctions 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.allwith two metadata-queue items serialises to ~2 s minimum.Both
metadataEnqueuecalls enter the same 1 RPS queue, so they execute sequentially despite thePromise.all. This is technically correct for rate limiting, but if latency matters forgetTokenPair, 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
getQuoteWithRetryandgetMetadataWithRetry(andgetSwapWithRetry) 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
| 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; | ||
| } | ||
| } |
There was a problem hiding this comment.
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 }>> { |
There was a problem hiding this comment.
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)
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
There was a problem hiding this comment.
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.
src/service.ts
Outdated
| const marketsResponse: any = await metadataEnqueue( | ||
| this.queueState, | ||
| `https://api.jup.ag/markets/v1?baseMint=${inputMint}"eMint=${outputMint}`, | ||
| this.getApiHeaders() |
There was a problem hiding this comment.
getTokenPair calls non-existent Jupiter Markets API endpoint
Medium Severity
The getTokenPair method queries https://api.jup.ag/markets/v1?baseMint=..."eMint=..., but Jupiter's API does not appear to have a /markets/v1 endpoint accepting baseMint/quoteMint query parameters. Jupiter's documented APIs include Ultra Swap, Tokens V2, Price v3, Metis Swap, and several others — none called "Markets v1" with these parameters. This will likely cause the metadataEnqueue call to receive a non-OK HTTP response, throwing an error and making the entire getTokenPair method non-functional at runtime.
Additional Locations (1)
src/service.ts
Outdated
| inputMint, | ||
| outputMint, | ||
| }: { | ||
| // Review: getCurrentPrices provides current snapshot; getHistoricalPrices removed as historical data no longer supporte... |
There was a problem hiding this comment.
Auto-generated review comments left in production code
Low Severity
Five // Review: comments are scattered throughout the file (lines 761, 786, 795, 897, 951). These appear to be auto-generated annotations from a code review tool — for example, one is truncated mid-word (...supporte...) and another is placed between a return statement and its closing brace. They add noise rather than useful documentation.
Additional Locations (2)
Explains reasoning for dismissed issues inline in code
There was a problem hiding this comment.
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.
| ### .prr/lessons.md | ||
|
|
||
| // Review: .prr/ is tool-managed directory; internal logs preserved for tool operation | ||
| - Fix for .prr/lessons.md:31 - tool made no changes without explanation - trying different approach |
There was a problem hiding this comment.
Internal PR review tool state file committed
Low Severity
The .prr/lessons.md file is auto-generated internal state from the prr PR review tool. It contains debugging artifacts like "Direct LLM CANNOT_FIX", "Direct LLM ALREADY_FIXED", and "tool made no changes without explanation - trying different approach" — none of which belong in the repository. The PR description doesn't mention this file, and .prr/ is not in .gitignore.
src/service.ts
Outdated
| function stopQueues(queueState: QueueState) { | ||
| if (queueState.timers.quotes) clearTimeout(queueState.timers.quotes); | ||
| if (queueState.timers.swaps) clearTimeout(queueState.timers.swaps); | ||
| if (queueState.timers.metadata) clearTimeout(queueState.timers.metadata); |
There was a problem hiding this comment.
Unused timer fields create dead cleanup code
Low Severity
The QueueState.timers type defines quotes, swaps, and metadata timer fields, but only timers.shared is ever assigned (in checkQueues). The corresponding clearTimeout calls in stopQueues for timers.quotes, timers.swaps, and timers.metadata are dead code — these fields are always undefined. This appears to be a vestige of an earlier per-queue-loop design that was replaced by the unified checkQueues approach.
Additional Locations (1)
Iteration 1 prr-fix:prrc_kwdootnhpm6pnatp prr-fix:prrc_kwdootnhpm6pnhy1
Changes:
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
Changes: - 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... - service.ts: ### API key not reset when service starts without key **Low 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... - 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... - service.ts: _⚠️ Potential issue_ | _🟠 Major_ **`stopQueues()` leaves enqueued items wit... - service.ts: _⚠️ Potential issue_ | _🟡 Minor_ **`getCurrentPrices` return type doesn't i... - service.ts: ### Public price API contract was broken **Medium Severity** <!-- DESCRIPTI... - service.ts: ### Stop leaves queued requests unresolved **Medium Severity** <!-- DESCRIP... - 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** <!-- ... - service.ts: ### Token volume field parsed incorrectly **Low Severity** <!-- DESCRIPTION... - 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: ### Historical prices return shape was broken **Medium Severity** <!-- DESC... - service.ts: ### Token pair silently masks API failures **Medium Severity** <!-- DESCRIP... - service.ts: ### Token pair failures are silently masked **Medium Severity** <!-- DESCRI... - 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: ### Sequential metadata queue makes `getTokenPair` very slow **Medium Severi... - service.ts: ### PR review tool comments left in production code **Low Severity** <!-- D... - service.ts: ### Three queue checker functions are unreachable dead code **Medium Severit... - service.ts: ### PR review tool comments committed as code **Low Severity** <!-- DESCRIP... - service.ts: ### Dead per-queue processor functions never called **Medium Severity** <!-... - service.ts: ### Automated review comments left in production code **Low Severity** <!--... - service.ts: ### `getTokenPair` bypasses rate-limiting queue with concurrent requests **H... - service.ts: ### Duplicate queue chains after rapid stop-start cycle **Low Severity** <!... - service.ts: ### Markets endpoint likely non-existent, breaking `getTokenPair` **Medium S... - service.ts: ### `getTokenPair` calls non-existent Jupiter Markets API endpoint **Medium ... - service.ts: ### Auto-generated review comments left in production code **Low Severity** ... - service.ts: ### Unused timer fields create dead cleanup code **Low Severity** <!-- DESC...
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
src/service.ts
Outdated
| url, | ||
| headers, | ||
| resolveHandle, | ||
| // Review: queueState.started validation occurs in enqueueWithHeaders before reaching this point |
There was a problem hiding this comment.
Auto-generated review comments left in production code
Medium Severity
Over a dozen auto-generated // Review: comments from the PRR tool are scattered throughout src/service.ts and build.ts. These appear at lines 94, 243, 365, 647, 699, 738, 763, 772, 805, 875, 887, 930 in service.ts and line 46 in build.ts. They are machine-generated annotations explaining code correctness and have no value for developers reading the source — they add noise and clutter to the codebase.
Additional Locations (2)
src/service.ts
Outdated
| const outputTokensResult = await metadataEnqueue( | ||
| this.queueState, | ||
| `https://api.jup.ag/tokens/v2/search?query=${outputMint}`, | ||
| this.getApiHeaders() |
There was a problem hiding this comment.
Two token lookups when one API call suffices
Medium Severity
getTokenPair makes two separate sequential metadataEnqueue calls to the Jupiter Tokens V2 Search API — one for inputMint and one for outputMint. Since the API supports comma-separated mint addresses in the query parameter, both tokens can be fetched in a single request. With the shared queue rate-limited to 1 request/second, this unnecessarily doubles the method's minimum latency and consumes an extra rate-limit slot.
| ### .prr/lessons.md | ||
|
|
||
| // Review: .prr/ is tool-managed directory; internal logs preserved for tool operation | ||
| - Fix for .prr/lessons.md:31 - tool made no changes without explanation - trying different approach |
There was a problem hiding this comment.
Internal PRR tool state file accidentally committed
Low Severity
The .prr/lessons.md file is an auto-generated internal state file from the PRR tool containing debugging logs, failed fix attempts ("tool made no changes without explanation"), and LLM interaction records ("Direct LLM CANNOT_FIX", "Direct LLM ALREADY_FIXED"). This internal tooling state exposes implementation details of the automated review process and has no place in the production repository.
Explains reasoning for dismissed issues inline in code
There was a problem hiding this comment.
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.
build.ts
Outdated
| // schedule a rebuild; build() handles in-progress/pending semantics | ||
| void build(); | ||
| }, 200); | ||
| }); |
There was a problem hiding this comment.
Double watch creates repeated rebuild loops
Medium Severity
In watch mode, build() runs Bun.build({ watch: watchRequested }) and the script also installs an fs.watch('src', { recursive: true }) that calls build() again on changes. This can create overlapping rebuild triggers and potentially repeated Bun.build watch registrations over time, leading to rebuild storms and resource leaks.
src/service.ts
Outdated
| }); | ||
| return Number(quote.outAmount) / 10 ** inputDecimals; // Convert using same decimals | ||
| // outAmount is in atomic units of the OUTPUT token, divide by output decimals | ||
| return Number((quote as any).outAmount) / 10 ** outputDecimals; |
There was a problem hiding this comment.
Token price conversion assumes output has 6 decimals
Medium Severity
getTokenPrice() now divides outAmount by outputDecimals but defaults outputDecimals to 6 even though callers can pass a non-USDC quoteMint with different decimals. This can silently return incorrect prices when quoteMint decimals differ from 6 and the caller doesn’t provide outputDecimals.
Iteration 1 prr-fix:prrc_kwdootnhpm6pp3qg prr-fix:prrc_kwdootnhpm6pp8ui
Iteration 2 prr-fix:prrc_kwdootnhpm6pp8ue
Changes: - 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 ... - build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ... - build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not... - 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... - 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... - service.ts: _⚠️ Potential issue_ | _🟠 Major_ **`stopQueues()` leaves enqueued items wit... - service.ts: _⚠️ Potential issue_ | _🟡 Minor_ **`getCurrentPrices` return type doesn't i... - service.ts: ### Public price API contract was broken **Medium Severity** <!-- DESCRIPTI... - service.ts: ### Stop leaves queued requests unresolved **Medium Severity** <!-- DESCRIP... - 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** <!-- ... - service.ts: ### Token volume field parsed incorrectly **Low Severity** <!-- DESCRIPTION... - 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: ### Historical prices return shape was broken **Medium Severity** <!-- DESC... - service.ts: ### Token pair silently masks API failures **Medium Severity** <!-- DESCRIP... - service.ts: ### Token pair failures are silently masked **Medium Severity** <!-- DESCRI... - 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: ### Sequential metadata queue makes `getTokenPair` very slow **Medium Severi... - service.ts: ### PR review tool comments left in production code **Low Severity** <!-- D... - service.ts: ### Three queue checker functions are unreachable dead code **Medium Severit... - service.ts: ### PR review tool comments committed as code **Low Severity** <!-- DESCRIP... - service.ts: ### Dead per-queue processor functions never called **Medium Severity** <!-... - service.ts: ### Automated review comments left in production code **Low Severity** <!--... - service.ts: ### `getTokenPair` bypasses rate-limiting queue with concurrent requests **H... - build.ts: ### Dev watch mode never activates in build script **Medium Severity** <!--... - service.ts: ### Duplicate queue chains after rapid stop-start cycle **Low Severity** <!... - build.ts: ### Watch mode creates exponentially growing duplicate watchers **Medium Sev... - service.ts: ### Markets endpoint likely non-existent, breaking `getTokenPair` **Medium S... - build.ts: ### Triple overlapping watch mechanisms cause redundant builds **Low Severit... - service.ts: ### `getTokenPair` calls non-existent Jupiter Markets API endpoint **Medium ... - service.ts: ### Auto-generated review comments left in production code **Low Severity** ... - service.ts: ### Unused timer fields create dead cleanup code **Low Severity** <!-- DESC... - service.ts: ### Auto-generated review comments left in production code **Medium Severity... - service.ts: ### Two token lookups when one API call suffices **Medium Severity** <!-- D... - build.ts: ### Double watch creates repeated rebuild loops **Medium Severity** <!-- DE... - service.ts: ### Token price conversion assumes output has 6 decimals **Medium Severity**...
Changes:
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored
**Medium Severity**
<!-- ...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- package.json: ### Dev watch mode never activates for source files
**Medium Severity**
<!-...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored
**Medium Severity**
<!-- ...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- package.json: ### Dev watch mode never activates for source files
**Medium Severity**
<!-...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
Changes:
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
Changes: - 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 ... - build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ... - build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not... - 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... - 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... - service.ts: _⚠️ Potential issue_ | _🟠 Major_ **`stopQueues()` leaves enqueued items wit... - service.ts: _⚠️ Potential issue_ | _🟡 Minor_ **`getCurrentPrices` return type doesn't i... - service.ts: ### Public price API contract was broken **Medium Severity** <!-- DESCRIPTI... - service.ts: ### Stop leaves queued requests unresolved **Medium Severity** <!-- DESCRIP... - 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** <!-- ... - service.ts: ### Token volume field parsed incorrectly **Low Severity** <!-- DESCRIPTION... - 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: ### Historical prices return shape was broken **Medium Severity** <!-- DESC... - service.ts: ### Token pair silently masks API failures **Medium Severity** <!-- DESCRIP... - service.ts: ### Token pair failures are silently masked **Medium Severity** <!-- DESCRI... - 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: ### Sequential metadata queue makes `getTokenPair` very slow **Medium Severi... - service.ts: ### PR review tool comments left in production code **Low Severity** <!-- D... - service.ts: ### Three queue checker functions are unreachable dead code **Medium Severit... - service.ts: ### PR review tool comments committed as code **Low Severity** <!-- DESCRIP... - service.ts: ### Dead per-queue processor functions never called **Medium Severity** <!-... - service.ts: ### Automated review comments left in production code **Low Severity** <!--... - service.ts: ### `getTokenPair` bypasses rate-limiting queue with concurrent requests **H... - build.ts: ### Dev watch mode never activates in build script **Medium Severity** <!--... - service.ts: ### Duplicate queue chains after rapid stop-start cycle **Low Severity** <!... - build.ts: ### Watch mode creates exponentially growing duplicate watchers **Medium Sev... - service.ts: ### Markets endpoint likely non-existent, breaking `getTokenPair` **Medium S... - build.ts: ### Triple overlapping watch mechanisms cause redundant builds **Low Severit... - service.ts: ### `getTokenPair` calls non-existent Jupiter Markets API endpoint **Medium ... - service.ts: ### Auto-generated review comments left in production code **Low Severity** ... - service.ts: ### Unused timer fields create dead cleanup code **Low Severity** <!-- DESC... - service.ts: ### Auto-generated review comments left in production code **Medium Severity... - service.ts: ### Two token lookups when one API call suffices **Medium Severity** <!-- D... - build.ts: ### Double watch creates repeated rebuild loops **Medium Severity** <!-- DE... - service.ts: ### Token price conversion assumes output has 6 decimals **Medium Severity**...
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| if (!queueState.started || queueState.runId !== currentRun) return; | ||
| checkQueues(queueState); | ||
| }, delayInMs); | ||
| } |
There was a problem hiding this comment.
runId guard fails to stop old loops
High Severity
checkQueues snapshots currentRun from queueState.runId and then immediately compares queueState.runId !== currentRun, which can never be true. This breaks the intended “invalidate old timeout chains” behavior: a stale setTimeout firing after a stop/start can start scheduling a second queue loop, causing duplicate requests and rate-limit violations.
Changes:
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
Changes:
- package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ...
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- package.json: ### Dev script `--watch` flag is silently ignored
**Medium Severity**
<!-- ...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- package.json: ### Dev watch mode never activates for source files
**Medium Severity**
<!-...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
Changes: - 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 ... - build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ... - build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not... - 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... - 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... - service.ts: _⚠️ Potential issue_ | _🟠 Major_ **`stopQueues()` leaves enqueued items wit... - service.ts: _⚠️ Potential issue_ | _🟡 Minor_ **`getCurrentPrices` return type doesn't i... - service.ts: ### Public price API contract was broken **Medium Severity** <!-- DESCRIPTI... - service.ts: ### Stop leaves queued requests unresolved **Medium Severity** <!-- DESCRIP... - 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** <!-- ... - service.ts: ### Token volume field parsed incorrectly **Low Severity** <!-- DESCRIPTION... - 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: ### Historical prices return shape was broken **Medium Severity** <!-- DESC... - service.ts: ### Token pair silently masks API failures **Medium Severity** <!-- DESCRIP... - service.ts: ### Token pair failures are silently masked **Medium Severity** <!-- DESCRI... - 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: ### Sequential metadata queue makes `getTokenPair` very slow **Medium Severi... - service.ts: ### PR review tool comments left in production code **Low Severity** <!-- D... - service.ts: ### Three queue checker functions are unreachable dead code **Medium Severit... - service.ts: ### PR review tool comments committed as code **Low Severity** <!-- DESCRIP... - service.ts: ### Dead per-queue processor functions never called **Medium Severity** <!-... - service.ts: ### Automated review comments left in production code **Low Severity** <!--... - service.ts: ### `getTokenPair` bypasses rate-limiting queue with concurrent requests **H... - build.ts: ### Dev watch mode never activates in build script **Medium Severity** <!--... - service.ts: ### Duplicate queue chains after rapid stop-start cycle **Low Severity** <!... - build.ts: ### Watch mode creates exponentially growing duplicate watchers **Medium Sev... - service.ts: ### Markets endpoint likely non-existent, breaking `getTokenPair` **Medium S... - build.ts: ### Triple overlapping watch mechanisms cause redundant builds **Low Severit... - service.ts: ### `getTokenPair` calls non-existent Jupiter Markets API endpoint **Medium ... - service.ts: ### Auto-generated review comments left in production code **Low Severity** ... - service.ts: ### Unused timer fields create dead cleanup code **Low Severity** <!-- DESC... - service.ts: ### Auto-generated review comments left in production code **Medium Severity... - service.ts: ### Two token lookups when one API call suffices **Medium Severity** <!-- D... - build.ts: ### Double watch creates repeated rebuild loops **Medium Severity** <!-- DE... - service.ts: ### Token price conversion assumes output has 6 decimals **Medium Severity**...
There was a problem hiding this comment.
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.
build.ts
Outdated
| console.log(`✅ Declarations generated in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`); | ||
| if (!existsSync(dtsPath)) { | ||
| throw new Error(`Type declarations missing at ${dtsPath}`); | ||
| } |
There was a problem hiding this comment.
Watch mode skips d.ts regeneration
Medium Severity
When --watch is used, Bun.build({ watch: true }) keeps rebuilding ESM outputs, but the script runs tsc only once for dist/index.d.ts and then never regenerates declarations on subsequent rebuilds. This can leave types (dist/index.d.ts) stale while dist/index.js updates, breaking consumers.
| ### .prr/lessons.md | ||
|
|
||
| // Review: .prr/ is tool-managed directory; internal logs preserved for tool operation | ||
| - Fix for .prr/lessons.md:31 - tool made no changes without explanation - trying different approach |
There was a problem hiding this comment.
Tool-generated PRR lessons committed
Low Severity
.prr/lessons.md is an auto-generated tool log file that includes internal review notes like ALREADY_FIXED/CANNOT_FIX and file/line references. Committing this kind of tool-managed artifact can unintentionally publish internal process data and create noisy diffs and merge conflicts unrelated to the plugin’s functionality.
Changes: - package.json: The `--watch` flag is passed to `build.ts`, but `build.ts` doesn't implement ... - package.json: package.json switches build/dev scripts to Bun, but the repo doesn’t declare ... - package.json: ### Dev script `--watch` flag is silently ignored **Medium Severity** <!-- ... - package.json: ### Dev watch mode never activates for source files **Medium Severity** <!-...
Iteration 1 prr-fix:prrc_kwdootnhpm6pqgdl
Changes:
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
- build.ts: ### Watch mode skips d.ts regeneration
**Medium Severity**
<!-- DESCRIPTION...
There was a problem hiding this comment.
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.
build.ts
Outdated
| } | ||
| : false, | ||
| external: externalDeps, | ||
| // Review: ESM build result checked for success and errors logged/thrown before proceeding |
There was a problem hiding this comment.
Review comment accidentally committed in build script
Low Severity
A code review comment // Review: ESM build result checked for success and errors logged/thrown before proceeding was left in the production code. This appears to be a reviewer's verification note rather than code documentation and wasn't removed before committing.
src/service.ts
Outdated
| this.getApiHeaders() | ||
| ); | ||
| const outputTokens = outputTokenResult as any[]; | ||
| const outputToken = outputTokens.find((t: any) => t.id === quoteMint) || outputTokens[0]; |
There was a problem hiding this comment.
Unreliable token metadata lookup using search fallback
Medium Severity
The getTokenPrice method uses the search endpoint /tokens/v2/search?query=${quoteMint} to fetch token decimals, then falls back to the first search result if no exact ID match is found. This inconsistency with getTokenPair (which uses direct ID lookup /tokens/v2/${mintAddress}) could return the wrong token's decimals if the search returns unexpected results, causing incorrect price calculations.
Changes:
- build.ts: The `if (true) { // Always generate .d.ts } else { ... }` block is dead code ...
- build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ...
- build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not...
- build.ts: ### Dead else branch due to `if (true)` conditional
**Low Severity**
<!-- D...
- build.ts: ### Build succeeds after declaration failures
**Medium Severity**
<!-- DESC...
- build.ts: _⚠️ Potential issue_ | _🟠 Major_
**Silently continuing after declaration ge...
- build.ts: ### Dev watch mode never activates in build script
**Medium Severity**
<!--...
- build.ts: ### Watch mode creates exponentially growing duplicate watchers
**Medium Sev...
- build.ts: ### Triple overlapping watch mechanisms cause redundant builds
**Low Severit...
- build.ts: ### Double watch creates repeated rebuild loops
**Medium Severity**
<!-- DE...
- build.ts: ### Watch mode skips d.ts regeneration
**Medium Severity**
<!-- DESCRIPTION...
Changes: - 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 ... - build.ts: `dev` runs `bun run build.ts --watch`, but build.ts never reads CLI args and ... - build.ts: build.ts invokes `tsc --project tsconfig.build.json`, but `typescript` is not... - 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... - 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... - service.ts: _⚠️ Potential issue_ | _🟠 Major_ **`stopQueues()` leaves enqueued items wit... - service.ts: _⚠️ Potential issue_ | _🟡 Minor_ **`getCurrentPrices` return type doesn't i... - service.ts: ### Public price API contract was broken **Medium Severity** <!-- DESCRIPTI... - service.ts: ### Stop leaves queued requests unresolved **Medium Severity** <!-- DESCRIP... - 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** <!-- ... - service.ts: ### Token volume field parsed incorrectly **Low Severity** <!-- DESCRIPTION... - 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: ### Historical prices return shape was broken **Medium Severity** <!-- DESC... - service.ts: ### Token pair silently masks API failures **Medium Severity** <!-- DESCRIP... - service.ts: ### Token pair failures are silently masked **Medium Severity** <!-- DESCRI... - 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: ### Sequential metadata queue makes `getTokenPair` very slow **Medium Severi... - service.ts: ### PR review tool comments left in production code **Low Severity** <!-- D... - service.ts: ### Three queue checker functions are unreachable dead code **Medium Severit... - service.ts: ### PR review tool comments committed as code **Low Severity** <!-- DESCRIP... - service.ts: ### Dead per-queue processor functions never called **Medium Severity** <!-... - service.ts: ### Automated review comments left in production code **Low Severity** <!--... - service.ts: ### `getTokenPair` bypasses rate-limiting queue with concurrent requests **H... - build.ts: ### Dev watch mode never activates in build script **Medium Severity** <!--... - service.ts: ### Duplicate queue chains after rapid stop-start cycle **Low Severity** <!... - build.ts: ### Watch mode creates exponentially growing duplicate watchers **Medium Sev... - service.ts: ### Markets endpoint likely non-existent, breaking `getTokenPair` **Medium S... - build.ts: ### Triple overlapping watch mechanisms cause redundant builds **Low Severit... - service.ts: ### `getTokenPair` calls non-existent Jupiter Markets API endpoint **Medium ... - service.ts: ### Auto-generated review comments left in production code **Low Severity** ... - service.ts: ### Unused timer fields create dead cleanup code **Low Severity** <!-- DESC... - service.ts: ### Auto-generated review comments left in production code **Medium Severity... - service.ts: ### Two token lookups when one API call suffices **Medium Severity** <!-- D... - build.ts: ### Double watch creates repeated rebuild loops **Medium Severity** <!-- DE... - service.ts: ### Token price conversion assumes output has 6 decimals **Medium Severity**... - build.ts: ### Watch mode skips d.ts regeneration **Medium Severity** <!-- DESCRIPTION... - build.ts: ### Review comment accidentally committed in build script **Low Severity** ... - service.ts: ### Unreliable token metadata lookup using search fallback **Medium Severity...
There was a problem hiding this comment.
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.
| return [ | ||
| { | ||
| timestamp: Math.max(inputPrice.timestamp, outputPrice.timestamp), | ||
| price: outputPrice.price / inputPrice.price, |
There was a problem hiding this comment.
Historical prices ratio formula is inverted
High Severity
The formula outputPrice.price / inputPrice.price computes the price of the output token denominated in the input token, which is the inverse of the standard trading pair convention. For a pair inputMint/outputMint, the expected price is "how many output tokens per input token" — consistent with getTokenPrice which uses output-per-input semantics. The correct formula is inputPrice.price / outputPrice.price. Relatedly, the zero-guard on line 694 checks inputPrice.price === 0, but with the corrected formula outputPrice.price becomes the denominator and needs the guard instead.
Additional Locations (1)
| ### .prr/lessons.md | ||
|
|
||
| // Review: .prr/ is tool-managed directory; internal logs preserved for tool operation | ||
| - Fix for .prr/lessons.md:31 - tool made no changes without explanation - trying different approach |
There was a problem hiding this comment.
PRR tool debugging artifacts accidentally committed
Low Severity
This file contains internal PRR tool debugging state — entries like "tool made no changes without explanation - trying different approach", "Direct LLM CANNOT_FIX", and "Direct LLM ALREADY_FIXED" are automated tool logs, not meaningful team documentation. While the file header says it can be committed for team sharing, the actual content is noisy internal state that clutters the repository without providing actionable lessons.


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
Changes core Jupiter networking behavior (API auth, queuing/rate limiting, caching) and alters price/pair endpoints, which could affect swap/quote correctness and runtime availability if the API key or response shapes differ.
Overview
Migrates Jupiter integration from
lite-api.jup.ag/legacy endpoints toapi.jup.ag, requiringJUPITER_API_KEYat service start and sendingx-api-keyon quote/swap/metadata requests.Reworks request handling into a shared, 1 req/sec, round-robin queue across quotes/swaps/metadata with retry/backoff, adds a TTL+size-bounded route cache keyed by mints/amount/slippage, and updates price helpers (token decimals resolution,
getTokenPairnow metadata-only,getHistoricalPricesnow returns a current snapshot viaprice/v3).Replaces
tsupwith a Bun-basedbuild.ts+tsconfig.build.jsonfor ESM builds and declaration generation, updatespackage.jsonscripts/engines, and expands.gitignore(also adds tool-managed.prr/lessons.md).Written by Cursor Bugbot for commit bd38849. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Improvements
Chores
Tests
Documentation
Greptile Overview
Greptile Summary
Migrates Jupiter API integration from
lite-api.jup.agtoapi.jup.agwith API key authentication viax-api-keyheader, sourced fromJUPITER_API_KEYruntime setting.Key Changes:
getApiHeaders()function to injectx-api-keyheader when API key is configuredhttps://api.jup.ag/swap/v1for quote and swap endpointsamountparameter for better cache granularitytsupbuild with custom Bun-basedbuild.tsthat runs ESM bundling + TypeScript declaration generationIssues Found:
getTokenPair()andgetHistoricalPrices()methods still call the oldhttps://public.jupiterapi.comendpoints, which may not accept the new API key headerdevscript references--watchflag, butbuild.tsdoesn't implement watch modebuild.ts(unreachable else branch due toif (true)condition)Confidence Score: 3/5
getTokenPair,getHistoricalPrices) still use old endpoints that may not work. Build system changes are functional despite minor issues with watch mode and dead code.src/service.ts- verify thatgetTokenPairandgetHistoricalPriceswork with the old endpoint or need migrationImportant Files Changed
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