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.
| 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
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
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}"eMint=${outputMint}`, | ||
| this.getApiHeaders() |
There was a problem hiding this comment.
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.
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]; |
There was a problem hiding this comment.
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)
src/service.ts
Outdated
| liquidity: number; | ||
| volume24h: number; | ||
| combinedTokenLiquidity: number; | ||
| combinedTokenVolume24h: number; |
There was a problem hiding this comment.
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)
src/service.ts
Outdated
| [mint: string]: { | ||
| prices: Array<{ timestamp: number; price: number }>; | ||
| }; | ||
| }> { |
There was a problem hiding this comment.
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)
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]; |
There was a problem hiding this comment.
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.
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]; |
There was a problem hiding this comment.
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)
| checkQuoteQueues(queueState); | ||
| checkSwapQueues(queueState); | ||
| checkMetadataQueues(queueState); | ||
| } |
There was a problem hiding this comment.
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)
| if (!queueState.started) return; | ||
| // 1 RPS basic tier; queue throttles to be respectful | ||
| queueState.timers.metadata = setTimeout(() => checkMetadataQueues(queueState), delayInMs) | ||
| } |
There was a problem hiding this comment.
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.
test_fail.ts
Outdated
| @@ -0,0 +1 @@ | |||
|
|
|||
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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)
test_fail.ts
Outdated
| @@ -0,0 +1 @@ | |||
|
|
|||
There was a problem hiding this comment.
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.
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]; |
There was a problem hiding this comment.
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)
| 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. |
There was a problem hiding this comment.
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)
test_fail.ts
Outdated
| @@ -0,0 +1 @@ | |||
|
|
|||
There was a problem hiding this comment.
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) | ||
| } |
There was a problem hiding this comment.
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)
| // 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 |
There was a problem hiding this comment.
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)
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
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.
| delayInMs -= took | ||
| if (delayInMs < 0) delayInMs = 0 | ||
| console.log('swap took', took.toLocaleString() + 'ms', 'delay now', delayInMs) | ||
| } |
There was a problem hiding this comment.
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)
| // 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 |
There was a problem hiding this comment.
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.


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.agand requiresJUPITER_API_KEYat service start, automatically injectingx-api-keyheaders 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 newgetCurrentPrices) and makesgetHistoricalPricesfall back to a current snapshot.Build tooling switches from
tsupto a Bunbuild.tsrunner plustsconfig.build.json, and housekeeping updates include expanded.gitignoreand a generated.prr/lessons.mdfile.Written by Cursor Bugbot for commit b981558. 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