Skip to content

Add website agent discovery metadata#453

Merged
frostney merged 10 commits into
mainfrom
t3code/agent-discovery-metadata-1
Apr 29, 2026
Merged

Add website agent discovery metadata#453
frostney merged 10 commits into
mainfrom
t3code/agent-discovery-metadata-1

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 29, 2026

Summary

  • add OAuth/OIDC, OAuth protected resource, MCP server card, and agent skills discovery routes under /.well-known
  • expose WebMCP tools for GocciaScript execute/test APIs with an 8 KiB code limit
  • document GocciaScript language subset constraints in the served SKILL.md

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gocciascript-homepage Ready Ready Preview, Comment Apr 29, 2026 3:43pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bce91e35-71f2-44c2-9466-e360e1790c2b

📥 Commits

Reviewing files that changed from the base of the PR and between 16381b7 and b61909f.

📒 Files selected for processing (1)
  • website/src/lib/goccia-api.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/src/lib/goccia-api.ts

📝 Walkthrough

Walkthrough

Adds multiple /.well-known discovery endpoints and builders, a Zod-based Goccia tool input schema with byte limits and validators, a WebMCP client tool integrator that validates and calls server APIs, updates the server run handler to use the validator, and expands tests for discovery and schema behavior.

Changes

Cohort / File(s) Summary
Discovery route handlers
website/src/app/.well-known/agent-skills/index.json/route.ts, website/src/app/.well-known/agent-skills/gocciascript-api/SKILL.md/route.ts, website/src/app/.well-known/mcp/server-card.json/route.ts, website/src/app/.well-known/oauth-authorization-server/route.ts, website/src/app/.well-known/oauth-protected-resource/route.ts, website/src/app/.well-known/jwks.json/route.ts
Added dynamic Next.js GET handlers that compute origin, return standardized JSON/Markdown payloads (OAuth metadata, protected-resource, JWKS, MCP server-card, agent-skills index), set Link headers; MCP server-card fetches latest release and falls back to nightly.
Agent discovery library
website/src/lib/agent-discovery.ts
New constants for well-known paths and Link header rels, absoluteUrl helper, and builder functions for OAuth metadata, protected-resource metadata, empty JWKS, MCP server-card (tool specs), SKILL.md generator, agent-skills index, sha256 digest, and release→MCP-version mapping.
Goccia tool schema & validation
website/src/lib/goccia-tool-schema.ts, website/package.json
Added Zod schema, MAX_GOCCIA_CODE_BYTES (8 KiB), MAX_GOCCIA_TOOL_REQUEST_BYTES, UTF‑8 length util, validation result mapping (MISSING_CODE, CODE_TOO_LARGE, INVALID_INPUT), gocciaRunInputSchema() JSON Schema generator, and added zod dependency.
Server API & handler changes
website/src/lib/goccia-api.ts
runHandler now parses unknown payloads and uses validateGocciaToolInput; enforces UTF‑8 code byte limit with 413 for CODE_TOO_LARGE, removes handler-side defaults for flags, extends TransportError union with INVALID_INPUT, and emits telemetry on size violations.
Client integration / WebMCP
website/src/components/webmcp-tools.tsx, website/src/app/layout.tsx
New client component WebMcpTools registers goccia.execute and goccia.test with navigator.modelContext (fallback to registerTool), validates inputs client-side, posts validated payloads to /api/execute or /api/test, and cleans up on unmount; RootLayout mounts the component.
Playground client changes
website/src/components/playground.tsx
Performs client-side validation before requests, shows validation errors without issuing network calls, and sends validated/normalized payloads when valid.
Tests
website/src/__tests__/agent-discovery.test.ts, website/src/__tests__/goccia-tool-schema.test.ts
Expanded tests covering well-known artifacts, Link headers, JWKS/MCP/skills builders and digests, release-tag mapping, and comprehensive validation/byte-length edge cases for tool schema and server behavior.

Sequence Diagram(s)

sequenceDiagram
  participant Browser as Browser (WebMcpTools)
  participant ModelCtx as navigator.modelContext / registerTool
  participant Validator as validateGocciaToolInput
  participant API as Server (/api/execute or /api/test)
  Browser->>ModelCtx: register tools (goccia.execute, goccia.test)
  Browser->>Validator: validate input payload
  alt validation ok
    Browser->>API: POST validated payload
    API->>Validator: validate server-side
    Validator-->>API: ok
    API-->>Browser: JSON result (200)
  else validation fails
    Validator-->>Browser: error (CODE_TOO_LARGE / INVALID_INPUT / MISSING_CODE)
    Browser-->>Browser: abort request, show error
  end
  Browser->>ModelCtx: cleanup on unmount (clearContext / unregister)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add website agent discovery metadata' directly and clearly summarizes the main change—adding discovery routes and metadata endpoints under /.well-known.
Description check ✅ Passed The description is directly related to the changeset, detailing the three core additions: OAuth/OIDC discovery routes, WebMCP tools exposure, and SKILL.md documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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


Review rate limit: 0/5 reviews remaining, refill in 55 minutes and 3 seconds.

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

@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation new feature New feature or request spec compliance Mismatch against official JavaScript/TypeScript specification labels Apr 29, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

Benchmark Results

407 benchmarks

Interpreted: 🟢 73 improved · 🔴 29 regressed · 305 unchanged · avg +2.0%
Bytecode: 🟢 66 improved · 🔴 42 regressed · 299 unchanged · avg +2.2%

arraybuffer.js — Interp: 🟢 4, 10 unch. · avg +1.8% · Bytecode: 14 unch. · avg +0.2%
Benchmark Interpreted Δ Bytecode Δ
create ArrayBuffer(0) 173,263 ops/sec [157,549..179,301] → 178,741 ops/sec [152,610..184,107] ~ overlap (+3.2%) 233,716 ops/sec [161,482..247,558] → 241,635 ops/sec [233,230..245,490] ~ overlap (+3.4%)
create ArrayBuffer(64) 173,719 ops/sec [171,955..174,479] → 172,398 ops/sec [170,698..179,641] ~ overlap (-0.8%) 227,834 ops/sec [222,567..233,758] → 229,270 ops/sec [224,782..230,389] ~ overlap (+0.6%)
create ArrayBuffer(1024) 149,403 ops/sec [147,865..150,537] → 151,901 ops/sec [146,302..152,752] ~ overlap (+1.7%) 186,937 ops/sec [185,842..188,923] → 186,202 ops/sec [171,407..190,276] ~ overlap (-0.4%)
create ArrayBuffer(8192) 80,867 ops/sec [78,996..82,166] → 83,085 ops/sec [82,440..83,509] 🟢 +2.7% 85,981 ops/sec [84,952..87,881] → 87,711 ops/sec [86,348..88,499] ~ overlap (+2.0%)
slice full buffer (64 bytes) 191,063 ops/sec [186,222..191,630] → 192,534 ops/sec [189,899..194,870] ~ overlap (+0.8%) 277,187 ops/sec [272,506..284,040] → 281,530 ops/sec [279,703..288,919] ~ overlap (+1.6%)
slice half buffer (512 of 1024 bytes) 171,977 ops/sec [168,584..172,231] → 172,831 ops/sec [171,095..175,560] ~ overlap (+0.5%) 244,134 ops/sec [243,444..245,025] → 244,113 ops/sec [242,871..245,567] ~ overlap (-0.0%)
slice with negative indices 157,042 ops/sec [155,865..160,004] → 161,905 ops/sec [160,303..162,520] 🟢 +3.1% 259,840 ops/sec [256,386..262,546] → 259,929 ops/sec [258,142..260,969] ~ overlap (+0.0%)
slice empty range 181,833 ops/sec [178,078..185,687] → 185,349 ops/sec [183,142..186,415] ~ overlap (+1.9%) 270,196 ops/sec [266,865..273,257] → 269,326 ops/sec [266,703..270,258] ~ overlap (-0.3%)
byteLength access 405,456 ops/sec [403,091..413,036] → 421,367 ops/sec [416,538..434,294] 🟢 +3.9% 746,469 ops/sec [731,696..763,717] → 741,142 ops/sec [735,313..742,894] ~ overlap (-0.7%)
Symbol.toStringTag access 338,487 ops/sec [335,069..349,700] → 352,248 ops/sec [348,226..354,769] ~ overlap (+4.1%) 485,583 ops/sec [480,293..496,129] → 479,606 ops/sec [473,178..484,093] ~ overlap (-1.2%)
ArrayBuffer.isView 248,077 ops/sec [243,362..252,212] → 250,047 ops/sec [245,043..255,695] ~ overlap (+0.8%) 370,672 ops/sec [367,308..377,193] → 369,832 ops/sec [365,977..371,677] ~ overlap (-0.2%)
clone ArrayBuffer(64) 168,336 ops/sec [167,315..168,733] → 170,839 ops/sec [169,417..172,386] 🟢 +1.5% 230,282 ops/sec [227,637..232,954] → 229,899 ops/sec [229,325..230,307] ~ overlap (-0.2%)
clone ArrayBuffer(1024) 145,351 ops/sec [142,743..146,706] → 145,700 ops/sec [143,356..148,233] ~ overlap (+0.2%) 189,619 ops/sec [188,204..190,659] → 189,586 ops/sec [187,491..190,499] ~ overlap (-0.0%)
clone ArrayBuffer inside object 118,778 ops/sec [117,894..121,974] → 121,354 ops/sec [118,049..122,887] ~ overlap (+2.2%) 154,453 ops/sec [150,890..155,439] → 152,102 ops/sec [150,836..153,803] ~ overlap (-1.5%)
arrays.js — Interp: 🟢 3, 🔴 1, 15 unch. · avg +0.9% · Bytecode: 🟢 3, 16 unch. · avg +0.7%
Benchmark Interpreted Δ Bytecode Δ
Array.from length 100 3,985 ops/sec [3,475..4,108] → 4,169 ops/sec [4,096..4,202] ~ overlap (+4.6%) 7,260 ops/sec [5,893..7,425] → 7,245 ops/sec [6,910..7,721] ~ overlap (-0.2%)
Array.from 10 elements 89,480 ops/sec [86,827..90,934] → 90,580 ops/sec [63,997..91,552] ~ overlap (+1.2%) 106,645 ops/sec [105,466..107,797] → 108,287 ops/sec [106,284..108,383] ~ overlap (+1.5%)
Array.of 10 elements 108,259 ops/sec [108,121..108,461] → 105,939 ops/sec [103,082..106,888] 🔴 -2.1% 137,943 ops/sec [136,507..138,799] → 137,094 ops/sec [135,519..139,041] ~ overlap (-0.6%)
spread into new array 132,485 ops/sec [130,523..134,497] → 135,821 ops/sec [132,350..137,037] ~ overlap (+2.5%) 83,446 ops/sec [82,528..84,268] → 86,118 ops/sec [85,017..86,433] 🟢 +3.2%
map over 50 elements 6,783 ops/sec [6,682..6,817] → 6,904 ops/sec [6,838..6,977] 🟢 +1.8% 13,189 ops/sec [13,003..13,301] → 13,512 ops/sec [13,418..13,619] 🟢 +2.4%
filter over 50 elements 6,269 ops/sec [6,252..6,275] → 6,459 ops/sec [6,352..6,490] 🟢 +3.0% 13,058 ops/sec [12,773..13,166] → 13,052 ops/sec [12,930..13,134] ~ overlap (-0.0%)
reduce sum 50 elements 7,080 ops/sec [7,029..7,132] → 7,383 ops/sec [7,209..7,411] 🟢 +4.3% 12,625 ops/sec [12,484..12,710] → 12,717 ops/sec [12,597..12,806] ~ overlap (+0.7%)
forEach over 50 elements 6,463 ops/sec [6,349..6,487] → 6,600 ops/sec [6,438..6,640] ~ overlap (+2.1%) 12,562 ops/sec [12,441..12,721] → 12,529 ops/sec [12,417..12,685] ~ overlap (-0.3%)
find in 50 elements 9,369 ops/sec [9,310..9,421] → 9,467 ops/sec [9,298..9,558] ~ overlap (+1.0%) 19,164 ops/sec [18,880..19,409] → 19,504 ops/sec [19,405..19,545] ~ overlap (+1.8%)
sort 20 elements 3,513 ops/sec [3,460..3,531] → 3,635 ops/sec [3,433..3,673] ~ overlap (+3.5%) 7,593 ops/sec [7,519..7,642] → 7,702 ops/sec [7,467..7,763] ~ overlap (+1.4%)
flat nested array 47,054 ops/sec [46,564..47,395] → 46,748 ops/sec [46,429..48,789] ~ overlap (-0.7%) 53,989 ops/sec [52,798..54,463] → 54,842 ops/sec [54,627..55,256] 🟢 +1.6%
flatMap 27,179 ops/sec [26,843..27,203] → 27,026 ops/sec [26,783..27,389] ~ overlap (-0.6%) 36,914 ops/sec [35,938..37,543] → 37,116 ops/sec [36,970..37,541] ~ overlap (+0.5%)
map inside map (5x5) 7,117 ops/sec [7,022..7,145] → 7,132 ops/sec [7,031..7,278] ~ overlap (+0.2%) 11,019 ops/sec [10,894..11,203] → 11,022 ops/sec [10,922..11,156] ~ overlap (+0.0%)
filter inside map (5x10) 4,919 ops/sec [4,828..4,998] → 4,932 ops/sec [4,905..4,981] ~ overlap (+0.3%) 8,927 ops/sec [8,832..9,029] → 8,864 ops/sec [8,824..9,021] ~ overlap (-0.7%)
reduce inside map (5x10) 5,862 ops/sec [5,712..5,884] → 5,759 ops/sec [5,741..5,818] ~ overlap (-1.8%) 9,771 ops/sec [9,656..9,916] → 9,650 ops/sec [9,574..9,667] ~ overlap (-1.2%)
forEach inside forEach (5x10) 5,196 ops/sec [5,166..5,254] → 5,221 ops/sec [5,023..5,267] ~ overlap (+0.5%) 9,886 ops/sec [9,783..9,964] → 9,951 ops/sec [9,920..10,029] ~ overlap (+0.7%)
find inside some (10x10) 4,171 ops/sec [4,156..4,217] → 4,149 ops/sec [4,133..4,182] ~ overlap (-0.5%) 7,997 ops/sec [7,876..8,025] → 7,959 ops/sec [7,942..8,055] ~ overlap (-0.5%)
map+filter chain nested (5x20) 1,560 ops/sec [1,522..1,578] → 1,547 ops/sec [1,522..1,576] ~ overlap (-0.8%) 2,931 ops/sec [2,920..2,948] → 2,975 ops/sec [2,923..2,990] ~ overlap (+1.5%)
reduce flatten (10x5) 17,240 ops/sec [16,999..17,492] → 16,957 ops/sec [16,849..17,062] ~ overlap (-1.6%) 7,876 ops/sec [7,826..7,992] → 7,966 ops/sec [7,789..8,011] ~ overlap (+1.1%)
async-await.js — Interp: 🟢 1, 5 unch. · avg +1.0% · Bytecode: 🔴 1, 5 unch. · avg -2.4%
Benchmark Interpreted Δ Bytecode Δ
single await 144,821 ops/sec [143,847..146,419] → 145,742 ops/sec [126,530..147,108] ~ overlap (+0.6%) 182,166 ops/sec [152,566..188,437] → 169,842 ops/sec [139,703..188,173] ~ overlap (-6.8%)
multiple awaits 69,037 ops/sec [68,626..69,363] → 69,884 ops/sec [68,645..70,132] ~ overlap (+1.2%) 82,355 ops/sec [80,313..82,636] → 82,027 ops/sec [79,664..82,971] ~ overlap (-0.4%)
await non-Promise value 282,847 ops/sec [278,843..284,104] → 287,977 ops/sec [286,933..289,504] 🟢 +1.8% 457,282 ops/sec [450,278..459,984] → 457,777 ops/sec [372,047..459,276] ~ overlap (+0.1%)
await with try/catch 134,221 ops/sec [131,633..137,636] → 138,094 ops/sec [135,252..139,895] ~ overlap (+2.9%) 181,099 ops/sec [178,713..184,081] → 173,430 ops/sec [171,931..174,943] 🔴 -4.2%
await Promise.all 22,893 ops/sec [22,702..23,047] → 22,733 ops/sec [22,522..23,188] ~ overlap (-0.7%) 25,356 ops/sec [25,044..25,527] → 25,058 ops/sec [24,771..25,202] ~ overlap (-1.2%)
nested async function call 76,533 ops/sec [75,533..77,692] → 76,601 ops/sec [75,707..77,277] ~ overlap (+0.1%) 109,528 ops/sec [106,119..112,129] → 107,326 ops/sec [106,467..107,920] ~ overlap (-2.0%)
async-generators.js — Interp: 2 unch. · avg -0.5% · Bytecode: 2 unch. · avg +0.4%
Benchmark Interpreted Δ Bytecode Δ
for-await-of over async generator 2,412 ops/sec [2,350..2,423] → 2,414 ops/sec [2,347..2,426] ~ overlap (+0.1%) 2,864 ops/sec [2,793..2,931] → 2,893 ops/sec [2,707..2,897] ~ overlap (+1.0%)
async generator with await in body 22,435 ops/sec [22,134..22,569] → 22,172 ops/sec [19,775..22,442] ~ overlap (-1.2%) 25,380 ops/sec [24,849..25,616] → 25,318 ops/sec [23,987..25,816] ~ overlap (-0.2%)
base64.js — Interp: 10 unch. · avg +0.3% · Bytecode: 10 unch. · avg +0.1%
Benchmark Interpreted Δ Bytecode Δ
short ASCII (13 chars) 4,243 ops/sec [4,187..4,251] → 4,291 ops/sec [4,199..4,365] ~ overlap (+1.1%) 4,701 ops/sec [4,661..4,752] → 4,721 ops/sec [4,690..4,798] ~ overlap (+0.4%)
medium ASCII (450 chars) 157 ops/sec [154..160] → 161 ops/sec [158..162] ~ overlap (+2.6%) 177 ops/sec [175..179] → 180 ops/sec [177..181] ~ overlap (+1.3%)
Latin-1 characters 6,145 ops/sec [4,326..6,182] → 6,228 ops/sec [6,077..6,333] ~ overlap (+1.3%) 6,946 ops/sec [6,831..7,111] → 7,009 ops/sec [6,980..7,087] ~ overlap (+0.9%)
short base64 (20 chars) 2,410 ops/sec [2,341..2,424] → 2,419 ops/sec [2,398..2,443] ~ overlap (+0.4%) 2,656 ops/sec [2,602..2,675] → 2,676 ops/sec [2,665..2,704] ~ overlap (+0.8%)
medium base64 (600 chars) 104 ops/sec [101..105] → 102 ops/sec [101..105] ~ overlap (-2.5%) 112 ops/sec [111..114] → 114 ops/sec [110..116] ~ overlap (+1.6%)
Latin-1 output 3,338 ops/sec [3,326..3,347] → 3,304 ops/sec [3,265..3,404] ~ overlap (-1.0%) 3,772 ops/sec [3,740..3,854] → 3,745 ops/sec [3,685..3,798] ~ overlap (-0.7%)
forgiving (no padding) 5,053 ops/sec [4,984..5,071] → 5,068 ops/sec [4,941..5,214] ~ overlap (+0.3%) 5,761 ops/sec [5,724..5,838] → 5,662 ops/sec [5,633..5,769] ~ overlap (-1.7%)
with whitespace 2,176 ops/sec [2,139..2,207] → 2,195 ops/sec [2,182..2,207] ~ overlap (+0.9%) 2,418 ops/sec [2,403..2,483] → 2,412 ops/sec [2,382..2,432] ~ overlap (-0.2%)
atob(btoa(short)) 1,544 ops/sec [1,486..1,559] → 1,544 ops/sec [1,530..1,573] ~ overlap (-0.0%) 1,693 ops/sec [1,684..1,711] → 1,684 ops/sec [1,674..1,711] ~ overlap (-0.5%)
atob(btoa(medium)) 63 ops/sec [63..64] → 63 ops/sec [63..65] ~ overlap (-0.3%) 70 ops/sec [66..71] → 69 ops/sec [67..70] ~ overlap (-0.7%)
classes.js — Interp: 🟢 1, 🔴 2, 28 unch. · avg -0.5% · Bytecode: 🔴 2, 29 unch. · avg +0.8%
Benchmark Interpreted Δ Bytecode Δ
simple class new 58,394 ops/sec [57,769..58,671] → 57,161 ops/sec [56,270..57,952] ~ overlap (-2.1%) 90,122 ops/sec [89,262..91,490] → 89,040 ops/sec [86,677..90,541] ~ overlap (-1.2%)
class with defaults 46,355 ops/sec [45,841..46,993] → 46,261 ops/sec [45,177..47,103] ~ overlap (-0.2%) 62,401 ops/sec [61,990..63,225] → 62,563 ops/sec [61,706..63,143] ~ overlap (+0.3%)
50 instances via Array.from 2,191 ops/sec [2,171..2,193] → 2,214 ops/sec [2,195..2,231] 🟢 +1.1% 3,943 ops/sec [3,913..4,014] → 3,815 ops/sec [3,778..3,847] 🔴 -3.2%
instance method call 27,623 ops/sec [27,448..27,995] → 28,153 ops/sec [26,859..28,413] ~ overlap (+1.9%) 46,572 ops/sec [46,109..46,863] → 45,499 ops/sec [45,058..46,598] ~ overlap (-2.3%)
static method call 42,940 ops/sec [42,586..43,321] → 42,873 ops/sec [42,653..43,417] ~ overlap (-0.2%) 81,641 ops/sec [80,115..83,433] → 83,062 ops/sec [81,258..84,426] ~ overlap (+1.7%)
single-level inheritance 23,079 ops/sec [22,806..23,666] → 23,323 ops/sec [22,924..23,783] ~ overlap (+1.1%) 33,587 ops/sec [33,085..34,402] → 34,537 ops/sec [34,277..34,960] ~ overlap (+2.8%)
two-level inheritance 20,037 ops/sec [19,777..20,223] → 20,239 ops/sec [19,984..20,725] ~ overlap (+1.0%) 26,645 ops/sec [25,924..27,570] → 27,695 ops/sec [27,219..28,293] ~ overlap (+3.9%)
private field access 30,324 ops/sec [29,433..30,611] → 30,549 ops/sec [30,168..31,039] ~ overlap (+0.7%) 46,678 ops/sec [46,221..47,433] → 47,634 ops/sec [47,319..48,244] ~ overlap (+2.0%)
private methods 33,555 ops/sec [32,993..33,756] → 33,962 ops/sec [33,438..34,148] ~ overlap (+1.2%) 50,333 ops/sec [49,823..51,130] → 50,810 ops/sec [50,390..51,198] ~ overlap (+0.9%)
getter/setter access 31,246 ops/sec [30,922..31,353] → 30,896 ops/sec [29,743..31,565] ~ overlap (-1.1%) 50,436 ops/sec [49,651..51,156] → 51,571 ops/sec [49,275..51,980] ~ overlap (+2.3%)
class decorator (identity) 41,037 ops/sec [39,552..42,020] → 41,517 ops/sec [40,384..41,919] ~ overlap (+1.2%) 52,939 ops/sec [52,660..53,880] → 51,520 ops/sec [51,238..51,881] 🔴 -2.7%
class decorator (wrapping) 24,641 ops/sec [24,320..24,662] → 24,407 ops/sec [24,140..24,703] ~ overlap (-1.0%) 28,188 ops/sec [27,571..28,758] → 29,116 ops/sec [28,550..29,865] ~ overlap (+3.3%)
identity method decorator 30,428 ops/sec [29,967..30,662] → 30,617 ops/sec [30,378..30,698] ~ overlap (+0.6%) 43,324 ops/sec [42,711..43,379] → 43,253 ops/sec [41,967..44,603] ~ overlap (-0.2%)
wrapping method decorator 25,049 ops/sec [24,791..25,295] → 24,516 ops/sec [24,406..24,783] 🔴 -2.1% 32,845 ops/sec [31,879..34,873] → 32,992 ops/sec [30,852..34,465] ~ overlap (+0.4%)
stacked method decorators (x3) 17,573 ops/sec [17,231..17,737] → 17,427 ops/sec [17,331..17,686] ~ overlap (-0.8%) 22,305 ops/sec [22,140..22,686] → 21,819 ops/sec [21,529..23,123] ~ overlap (-2.2%)
identity field decorator 34,187 ops/sec [33,756..35,459] → 33,781 ops/sec [33,277..34,834] ~ overlap (-1.2%) 38,757 ops/sec [37,858..39,988] → 39,178 ops/sec [38,833..40,348] ~ overlap (+1.1%)
field initializer decorator 28,637 ops/sec [27,685..29,293] → 28,404 ops/sec [27,920..28,917] ~ overlap (-0.8%) 34,180 ops/sec [32,904..36,044] → 35,017 ops/sec [34,156..35,829] ~ overlap (+2.5%)
getter decorator (identity) 31,165 ops/sec [31,106..31,486] → 30,747 ops/sec [30,404..30,974] 🔴 -1.3% 38,457 ops/sec [38,248..38,914] → 38,793 ops/sec [37,126..40,094] ~ overlap (+0.9%)
setter decorator (identity) 26,132 ops/sec [25,592..26,308] → 25,739 ops/sec [25,427..25,954] ~ overlap (-1.5%) 32,398 ops/sec [31,931..32,902] → 32,608 ops/sec [32,322..33,220] ~ overlap (+0.6%)
static method decorator 32,301 ops/sec [32,180..32,378] → 31,913 ops/sec [31,685..32,412] ~ overlap (-1.2%) 42,059 ops/sec [41,325..43,692] → 43,831 ops/sec [42,437..44,660] ~ overlap (+4.2%)
static field decorator 38,925 ops/sec [38,386..40,016] → 38,353 ops/sec [37,976..39,193] ~ overlap (-1.5%) 43,833 ops/sec [42,318..45,644] → 47,351 ops/sec [44,996..49,798] ~ overlap (+8.0%)
private method decorator 25,353 ops/sec [25,234..25,736] → 25,365 ops/sec [25,121..25,719] ~ overlap (+0.0%) 37,212 ops/sec [36,214..38,237] → 37,447 ops/sec [36,744..38,645] ~ overlap (+0.6%)
private field decorator 28,750 ops/sec [28,427..29,103] → 28,173 ops/sec [27,955..28,594] ~ overlap (-2.0%) 32,737 ops/sec [32,338..33,595] → 34,193 ops/sec [33,005..34,684] ~ overlap (+4.4%)
plain auto-accessor (no decorator) 48,968 ops/sec [47,856..50,580] → 48,589 ops/sec [47,952..50,025] ~ overlap (-0.8%) 53,215 ops/sec [46,883..56,100] → 49,552 ops/sec [48,497..50,847] ~ overlap (-6.9%)
auto-accessor with decorator 27,784 ops/sec [27,397..28,371] → 27,440 ops/sec [26,865..28,127] ~ overlap (-1.2%) 30,527 ops/sec [29,948..31,988] → 32,167 ops/sec [30,340..33,554] ~ overlap (+5.4%)
decorator writing metadata 22,648 ops/sec [21,871..22,696] → 21,606 ops/sec [21,412..22,104] ~ overlap (-4.6%) 26,208 ops/sec [25,773..26,401] → 26,357 ops/sec [25,759..26,943] ~ overlap (+0.6%)
static getter read 57,083 ops/sec [56,818..57,695] → 56,691 ops/sec [56,175..57,748] ~ overlap (-0.7%) 82,923 ops/sec [82,213..84,961] → 84,700 ops/sec [83,571..85,620] ~ overlap (+2.1%)
static getter/setter pair 41,715 ops/sec [41,304..42,586] → 42,151 ops/sec [41,880..42,268] ~ overlap (+1.0%) 60,241 ops/sec [58,341..62,806] → 58,118 ops/sec [56,796..59,191] ~ overlap (-3.5%)
inherited static getter 34,472 ops/sec [34,054..34,620] → 34,898 ops/sec [34,555..35,676] ~ overlap (+1.2%) 43,511 ops/sec [42,662..44,451] → 43,270 ops/sec [42,619..44,099] ~ overlap (-0.6%)
inherited static setter 37,430 ops/sec [36,243..37,964] → 37,477 ops/sec [36,782..38,095] ~ overlap (+0.1%) 47,955 ops/sec [45,411..49,345] → 47,292 ops/sec [45,965..47,803] ~ overlap (-1.4%)
inherited static getter with this binding 30,796 ops/sec [30,611..31,351] → 30,505 ops/sec [29,860..31,230] ~ overlap (-0.9%) 40,288 ops/sec [39,854..40,819] → 40,677 ops/sec [39,697..41,331] ~ overlap (+1.0%)
closures.js — Interp: 🟢 2, 9 unch. · avg +1.4% · Bytecode: 🟢 1, 10 unch. · avg -1.2%
Benchmark Interpreted Δ Bytecode Δ
closure over single variable 46,853 ops/sec [45,773..47,597] → 48,537 ops/sec [48,220..49,060] 🟢 +3.6% 159,113 ops/sec [157,992..162,463] → 158,091 ops/sec [155,926..161,290] ~ overlap (-0.6%)
closure over multiple variables 47,684 ops/sec [47,300..48,571] → 48,517 ops/sec [48,144..48,798] ~ overlap (+1.7%) 149,342 ops/sec [147,070..151,256] → 146,893 ops/sec [145,076..150,985] ~ overlap (-1.6%)
nested closures 52,882 ops/sec [52,217..53,122] → 52,956 ops/sec [52,418..53,668] ~ overlap (+0.1%) 150,092 ops/sec [148,750..152,528] → 147,975 ops/sec [146,280..152,445] ~ overlap (-1.4%)
function as argument 34,407 ops/sec [34,246..34,629] → 34,826 ops/sec [34,297..35,200] ~ overlap (+1.2%) 162,323 ops/sec [161,567..164,766] → 160,679 ops/sec [155,865..163,733] ~ overlap (-1.0%)
function returning function 44,566 ops/sec [44,023..44,983] → 44,737 ops/sec [44,334..45,527] ~ overlap (+0.4%) 177,660 ops/sec [174,342..180,732] → 171,536 ops/sec [167,393..177,655] ~ overlap (-3.4%)
compose two functions 27,853 ops/sec [27,360..28,141] → 27,932 ops/sec [27,692..28,078] ~ overlap (+0.3%) 100,513 ops/sec [99,138..106,075] → 100,145 ops/sec [99,797..101,011] ~ overlap (-0.4%)
fn.call 61,431 ops/sec [60,537..62,281] → 62,481 ops/sec [62,271..62,910] ~ overlap (+1.7%) 105,402 ops/sec [103,786..108,996] → 105,682 ops/sec [103,052..107,876] ~ overlap (+0.3%)
fn.apply 48,628 ops/sec [48,075..49,073] → 49,934 ops/sec [49,673..50,099] 🟢 +2.7% 100,907 ops/sec [99,207..101,575] → 102,120 ops/sec [101,704..102,831] 🟢 +1.2%
fn.bind 58,108 ops/sec [57,916..59,812] → 59,511 ops/sec [58,524..59,874] ~ overlap (+2.4%) 184,851 ops/sec [182,389..186,582] → 182,704 ops/sec [179,733..183,701] ~ overlap (-1.2%)
recursive sum to 50 4,083 ops/sec [4,061..4,110] → 4,090 ops/sec [4,056..4,137] ~ overlap (+0.2%) 22,107 ops/sec [21,028..22,660] → 21,262 ops/sec [21,058..21,380] ~ overlap (-3.8%)
recursive tree traversal 7,370 ops/sec [7,317..7,373] → 7,453 ops/sec [7,341..7,521] ~ overlap (+1.1%) 21,821 ops/sec [20,787..22,775] → 21,526 ops/sec [21,341..22,586] ~ overlap (-1.3%)
collections.js — Interp: 🟢 1, 🔴 5, 6 unch. · avg -1.1% · Bytecode: 🟢 2, 🔴 1, 9 unch. · avg +0.2%
Benchmark Interpreted Δ Bytecode Δ
add 50 elements 3,061 ops/sec [3,051..3,080] → 3,028 ops/sec [3,018..3,046] 🔴 -1.1% 4,046 ops/sec [3,927..4,096] → 3,954 ops/sec [3,927..3,956] ~ overlap (-2.3%)
has lookup (50 elements) 44,587 ops/sec [44,246..45,354] → 43,726 ops/sec [43,480..43,765] 🔴 -1.9% 55,378 ops/sec [54,726..57,175] → 55,131 ops/sec [54,788..55,202] ~ overlap (-0.4%)
delete elements 24,458 ops/sec [24,341..24,734] → 23,772 ops/sec [23,690..23,808] 🔴 -2.8% 29,212 ops/sec [28,945..29,786] → 28,851 ops/sec [27,895..29,387] ~ overlap (-1.2%)
forEach iteration 5,468 ops/sec [5,446..5,526] → 5,599 ops/sec [5,535..5,639] 🟢 +2.4% 9,528 ops/sec [9,482..9,611] → 9,418 ops/sec [9,284..9,476] 🔴 -1.2%
spread to array 16,246 ops/sec [15,907..16,806] → 16,155 ops/sec [16,048..16,349] ~ overlap (-0.6%) 118,148 ops/sec [117,043..118,334] → 117,587 ops/sec [111,589..119,986] ~ overlap (-0.5%)
deduplicate array 21,338 ops/sec [20,911..21,407] → 21,085 ops/sec [20,930..21,296] ~ overlap (-1.2%) 40,113 ops/sec [39,486..40,592] → 39,974 ops/sec [39,330..40,604] ~ overlap (-0.3%)
set 50 entries 2,221 ops/sec [2,181..2,268] → 2,200 ops/sec [2,174..2,223] ~ overlap (-0.9%) 3,009 ops/sec [2,976..3,075] → 3,007 ops/sec [2,935..3,072] ~ overlap (-0.1%)
get lookup (50 entries) 42,879 ops/sec [42,543..43,386] → 41,533 ops/sec [41,287..41,775] 🔴 -3.1% 50,717 ops/sec [49,789..51,955] → 50,649 ops/sec [49,440..51,177] ~ overlap (-0.1%)
has check 62,636 ops/sec [60,688..63,025] → 60,980 ops/sec [59,423..61,285] ~ overlap (-2.6%) 76,300 ops/sec [75,680..77,277] → 76,017 ops/sec [74,287..76,890] ~ overlap (-0.4%)
delete entries 23,730 ops/sec [23,117..24,061] → 22,731 ops/sec [22,708..22,860] 🔴 -4.2% 26,677 ops/sec [26,299..26,838] → 27,389 ops/sec [27,183..27,774] 🟢 +2.7%
forEach iteration 5,441 ops/sec [5,309..5,540] → 5,559 ops/sec [5,466..5,888] ~ overlap (+2.2%) 9,457 ops/sec [9,327..9,614] → 9,664 ops/sec [9,588..9,755] ~ overlap (+2.2%)
keys/values/entries 4,482 ops/sec [4,454..4,505] → 4,507 ops/sec [4,386..4,727] ~ overlap (+0.6%) 15,391 ops/sec [15,042..15,485] → 16,007 ops/sec [15,893..16,140] 🟢 +4.0%
csv.js — Interp: 🔴 1, 12 unch. · avg -0.6% · Bytecode: 🟢 2, 🔴 1, 10 unch. · avg +0.3%
Benchmark Interpreted Δ Bytecode Δ
parse simple 3-column CSV 47,191 ops/sec [46,938..47,963] → 48,389 ops/sec [47,625..48,572] ~ overlap (+2.5%) 55,407 ops/sec [54,917..55,704] → 55,842 ops/sec [55,484..56,007] ~ overlap (+0.8%)
parse 10-row CSV 13,217 ops/sec [13,103..13,326] → 13,251 ops/sec [13,083..13,654] ~ overlap (+0.3%) 15,265 ops/sec [15,211..15,319] → 15,329 ops/sec [15,154..15,741] ~ overlap (+0.4%)
parse 100-row CSV 2,071 ops/sec [1,985..2,110] → 2,058 ops/sec [2,034..2,089] ~ overlap (-0.6%) 2,344 ops/sec [2,280..2,354] → 2,359 ops/sec [2,302..2,398] ~ overlap (+0.6%)
parse CSV with quoted fields 69,101 ops/sec [67,188..71,212] → 69,024 ops/sec [68,339..70,234] ~ overlap (-0.1%) 79,020 ops/sec [78,257..79,432] → 81,455 ops/sec [81,352..81,555] 🟢 +3.1%
parse without headers (array of arrays) 5,890 ops/sec [5,640..6,054] → 5,855 ops/sec [5,804..5,939] ~ overlap (-0.6%) 6,416 ops/sec [6,395..6,456] → 6,499 ops/sec [6,473..6,541] 🟢 +1.3%
parse with semicolon delimiter 9,706 ops/sec [9,535..10,411] → 9,689 ops/sec [9,558..9,709] ~ overlap (-0.2%) 10,968 ops/sec [10,923..11,115] → 10,964 ops/sec [10,713..11,082] ~ overlap (-0.0%)
stringify array of objects 66,887 ops/sec [65,822..67,817] → 66,759 ops/sec [65,573..68,200] ~ overlap (-0.2%) 82,515 ops/sec [81,411..82,775] → 81,589 ops/sec [81,072..81,961] ~ overlap (-1.1%)
stringify array of arrays 24,432 ops/sec [23,678..25,027] → 24,115 ops/sec [24,082..24,127] ~ overlap (-1.3%) 27,471 ops/sec [27,339..27,765] → 26,785 ops/sec [26,266..27,162] 🔴 -2.5%
stringify with values needing escaping 49,851 ops/sec [48,588..50,514] → 48,872 ops/sec [48,388..49,928] ~ overlap (-2.0%) 59,228 ops/sec [58,618..59,400] → 59,482 ops/sec [59,344..59,772] ~ overlap (+0.4%)
reviver converts numbers 1,361 ops/sec [1,340..1,396] → 1,349 ops/sec [1,347..1,379] ~ overlap (-0.8%) 1,679 ops/sec [1,668..1,705] → 1,691 ops/sec [1,671..1,722] ~ overlap (+0.7%)
reviver filters empty to null 11,032 ops/sec [10,984..11,138] → 11,112 ops/sec [10,958..11,248] ~ overlap (+0.7%) 14,698 ops/sec [14,561..14,845] → 14,882 ops/sec [14,800..14,980] ~ overlap (+1.2%)
parse then stringify 8,740 ops/sec [8,596..8,866] → 8,479 ops/sec [8,413..8,539] 🔴 -3.0% 9,336 ops/sec [9,172..9,379] → 9,287 ops/sec [9,223..9,440] ~ overlap (-0.5%)
stringify then parse 8,367 ops/sec [8,247..8,512] → 8,138 ops/sec [8,052..8,346] ~ overlap (-2.7%) 9,187 ops/sec [8,984..9,251] → 9,160 ops/sec [9,068..9,238] ~ overlap (-0.3%)
destructuring.js — Interp: 🟢 7, 🔴 1, 14 unch. · avg +2.4% · Bytecode: 🟢 6, 16 unch. · avg +2.7%
Benchmark Interpreted Δ Bytecode Δ
simple array destructuring 169,829 ops/sec [157,441..173,388] → 174,188 ops/sec [171,066..175,587] ~ overlap (+2.6%) 128,978 ops/sec [125,053..130,494] → 127,469 ops/sec [126,656..127,843] ~ overlap (-1.2%)
with rest element 115,128 ops/sec [113,342..115,727] → 117,475 ops/sec [113,580..119,238] ~ overlap (+2.0%) 96,055 ops/sec [94,885..96,989] → 94,654 ops/sec [93,488..96,770] ~ overlap (-1.5%)
with defaults 168,612 ops/sec [168,367..169,095] → 175,526 ops/sec [172,396..176,896] 🟢 +4.1% 152,925 ops/sec [149,585..153,498] → 149,101 ops/sec [146,928..151,318] ~ overlap (-2.5%)
skip elements 177,298 ops/sec [176,611..178,241] → 184,168 ops/sec [181,718..185,733] 🟢 +3.9% 139,959 ops/sec [138,124..141,792] → 138,084 ops/sec [132,476..148,471] ~ overlap (-1.3%)
nested array destructuring 83,222 ops/sec [82,994..86,077] → 85,742 ops/sec [85,711..85,865] ~ overlap (+3.0%) 46,268 ops/sec [44,547..47,751] → 47,949 ops/sec [47,184..49,875] ~ overlap (+3.6%)
swap variables 210,169 ops/sec [208,451..212,369] → 217,752 ops/sec [213,888..220,051] 🟢 +3.6% 169,637 ops/sec [160,676..174,316] → 172,748 ops/sec [169,456..176,014] ~ overlap (+1.8%)
simple object destructuring 140,321 ops/sec [139,699..141,397] → 142,934 ops/sec [141,708..146,355] 🟢 +1.9% 185,378 ops/sec [177,465..191,881] → 188,965 ops/sec [182,727..197,283] ~ overlap (+1.9%)
with defaults 154,549 ops/sec [154,334..155,599] → 160,788 ops/sec [157,237..162,910] 🟢 +4.0% 248,203 ops/sec [243,946..249,948] → 254,503 ops/sec [250,372..260,362] 🟢 +2.5%
with renaming 148,834 ops/sec [146,741..150,619] → 151,641 ops/sec [148,327..154,468] ~ overlap (+1.9%) 185,961 ops/sec [176,963..191,753] → 193,777 ops/sec [189,617..195,842] ~ overlap (+4.2%)
nested object destructuring 75,641 ops/sec [74,445..76,120] → 78,178 ops/sec [76,889..79,362] 🟢 +3.4% 93,058 ops/sec [90,758..93,393] → 96,470 ops/sec [95,734..97,100] 🟢 +3.7%
rest properties 54,611 ops/sec [54,441..54,927] → 56,578 ops/sec [54,652..58,127] ~ overlap (+3.6%) 82,399 ops/sec [81,394..82,902] → 83,168 ops/sec [82,224..87,993] ~ overlap (+0.9%)
object parameter 41,816 ops/sec [41,713..42,624] → 40,922 ops/sec [40,726..41,142] 🔴 -2.1% 73,969 ops/sec [73,155..74,493] → 75,888 ops/sec [74,000..77,354] ~ overlap (+2.6%)
array parameter 52,801 ops/sec [52,565..53,012] → 53,568 ops/sec [53,271..53,995] 🟢 +1.5% 63,508 ops/sec [61,136..64,288] → 66,578 ops/sec [63,416..67,373] ~ overlap (+4.8%)
mixed destructuring in map 12,107 ops/sec [11,974..12,305] → 12,237 ops/sec [12,108..12,518] ~ overlap (+1.1%) 17,648 ops/sec [17,357..18,011] → 19,843 ops/sec [19,340..20,735] 🟢 +12.4%
forEach with array destructuring 26,431 ops/sec [25,027..26,683] → 27,081 ops/sec [25,696..28,256] ~ overlap (+2.5%) 24,140 ops/sec [23,884..24,982] → 23,873 ops/sec [23,035..24,241] ~ overlap (-1.1%)
map with array destructuring 27,887 ops/sec [27,127..28,010] → 28,415 ops/sec [27,357..28,990] ~ overlap (+1.9%) 22,977 ops/sec [22,541..23,394] → 24,002 ops/sec [23,105..24,790] ~ overlap (+4.5%)
filter with array destructuring 28,389 ops/sec [27,895..29,108] → 29,020 ops/sec [28,649..29,573] ~ overlap (+2.2%) 24,658 ops/sec [23,450..25,462] → 25,462 ops/sec [25,010..26,044] ~ overlap (+3.3%)
reduce with array destructuring 31,019 ops/sec [30,949..31,591] → 31,508 ops/sec [31,163..32,112] ~ overlap (+1.6%) 25,208 ops/sec [24,604..25,703] → 26,407 ops/sec [25,919..26,519] 🟢 +4.8%
map with object destructuring 26,692 ops/sec [26,332..28,322] → 27,478 ops/sec [27,255..28,337] ~ overlap (+2.9%) 39,468 ops/sec [39,302..39,830] → 43,721 ops/sec [43,172..45,792] 🟢 +10.8%
map with nested destructuring 22,810 ops/sec [22,764..24,014] → 23,627 ops/sec [23,283..24,479] ~ overlap (+3.6%) 40,575 ops/sec [39,953..41,460] → 39,885 ops/sec [39,597..40,337] ~ overlap (-1.7%)
map with rest in destructuring 17,374 ops/sec [17,169..18,312] → 17,632 ops/sec [17,228..18,093] ~ overlap (+1.5%) 12,917 ops/sec [12,676..12,977] → 12,975 ops/sec [12,746..13,108] ~ overlap (+0.4%)
map with defaults in destructuring 21,365 ops/sec [21,139..22,080] → 21,768 ops/sec [21,467..22,347] ~ overlap (+1.9%) 30,797 ops/sec [30,409..31,972] → 32,587 ops/sec [32,391..33,284] 🟢 +5.8%
fibonacci.js — Interp: 🟢 2, 6 unch. · avg +0.9% · Bytecode: 🟢 1, 🔴 1, 6 unch. · avg +0.6%
Benchmark Interpreted Δ Bytecode Δ
recursive fib(15) 109 ops/sec [107..110] → 110 ops/sec [106..115] ~ overlap (+1.0%) 598 ops/sec [585..619] → 604 ops/sec [575..637] ~ overlap (+0.9%)
recursive fib(20) 10 ops/sec [10..10] → 10 ops/sec [10..10] 🟢 +2.5% 53 ops/sec [53..53] → 52 ops/sec [52..54] ~ overlap (-0.6%)
recursive fib(15) typed 107 ops/sec [106..110] → 110 ops/sec [109..114] ~ overlap (+2.7%) 491 ops/sec [489..492] → 484 ops/sec [481..486] 🔴 -1.5%
recursive fib(20) typed 10 ops/sec [10..10] → 10 ops/sec [10..10] ~ overlap (+1.8%) 45 ops/sec [44..46] → 44 ops/sec [44..45] ~ overlap (-2.4%)
iterative fib(20) via reduce 4,741 ops/sec [4,679..4,785] → 4,847 ops/sec [4,829..4,930] 🟢 +2.2% 10,223 ops/sec [9,809..10,468] → 10,358 ops/sec [10,218..10,920] ~ overlap (+1.3%)
iterator fib(20) 3,715 ops/sec [3,672..3,775] → 3,724 ops/sec [3,684..3,760] ~ overlap (+0.2%) 8,667 ops/sec [8,564..8,702] → 8,807 ops/sec [8,481..8,979] ~ overlap (+1.6%)
iterator fib(20) via Iterator.from + take 5,237 ops/sec [5,187..5,329] → 5,208 ops/sec [5,141..5,216] ~ overlap (-0.5%) 7,438 ops/sec [7,326..7,622] → 7,749 ops/sec [7,625..7,884] 🟢 +4.2%
iterator fib(20) last value via reduce 4,092 ops/sec [3,982..4,128] → 3,992 ops/sec [3,969..4,025] ~ overlap (-2.4%) 5,754 ops/sec [5,521..6,017] → 5,819 ops/sec [5,761..5,870] ~ overlap (+1.1%)
float16array.js — Interp: 🟢 8, 🔴 1, 23 unch. · avg +1.5% · Bytecode: 🟢 14, 🔴 4, 14 unch. · avg +11.9%
Benchmark Interpreted Δ Bytecode Δ
new Float16Array(0) 135,934 ops/sec [134,164..138,363] → 136,147 ops/sec [134,258..136,338] ~ overlap (+0.2%) 169,754 ops/sec [165,180..171,191] → 165,210 ops/sec [162,681..165,557] ~ overlap (-2.7%)
new Float16Array(100) 130,977 ops/sec [128,879..131,556] → 131,079 ops/sec [124,706..132,721] ~ overlap (+0.1%) 161,568 ops/sec [159,472..164,926] → 159,047 ops/sec [156,294..160,312] ~ overlap (-1.6%)
new Float16Array(1000) 112,024 ops/sec [111,235..112,946] → 110,501 ops/sec [108,977..112,281] ~ overlap (-1.4%) 127,372 ops/sec [124,744..128,481] → 124,349 ops/sec [123,308..126,041] ~ overlap (-2.4%)
Float16Array.from([...100]) 84,495 ops/sec [84,453..84,873] → 84,252 ops/sec [83,458..84,745] ~ overlap (-0.3%) 100,247 ops/sec [97,802..103,051] → 95,962 ops/sec [94,929..96,185] 🔴 -4.3%
Float16Array.of(1.5, 2.5, 3.5, 4.5, 5.5) 129,486 ops/sec [109,923..133,430] → 131,123 ops/sec [130,613..131,441] ~ overlap (+1.3%) 120,801 ops/sec [117,402..121,875] → 116,784 ops/sec [115,807..117,603] ~ overlap (-3.3%)
new Float16Array(float64Array) 89,596 ops/sec [87,551..91,182] → 90,848 ops/sec [88,655..91,201] ~ overlap (+1.4%) 109,124 ops/sec [105,251..110,729] → 103,560 ops/sec [102,399..103,881] 🔴 -5.1%
sequential write 100 elements 1,428 ops/sec [1,400..1,443] → 1,461 ops/sec [1,441..1,515] ~ overlap (+2.4%) 4,345 ops/sec [4,268..4,424] → 4,145 ops/sec [4,074..4,214] 🔴 -4.6%
sequential read 100 elements 1,595 ops/sec [1,525..1,616] → 1,604 ops/sec [1,602..1,614] ~ overlap (+0.5%) 5,447 ops/sec [5,309..5,469] → 5,382 ops/sec [5,366..5,417] ~ overlap (-1.2%)
write special values (NaN, Inf, -0) 64,231 ops/sec [63,419..64,832] → 66,821 ops/sec [66,043..67,370] 🟢 +4.0% 133,308 ops/sec [129,412..136,131] → 128,200 ops/sec [127,177..128,405] 🔴 -3.8%
Float16Array write 1,469 ops/sec [1,459..1,471] → 1,466 ops/sec [1,453..1,495] ~ overlap (-0.2%) 4,229 ops/sec [4,205..4,280] → 4,237 ops/sec [4,160..4,269] ~ overlap (+0.2%)
Float32Array write 1,491 ops/sec [1,482..1,494] → 1,477 ops/sec [1,461..1,491] ~ overlap (-0.9%) 4,251 ops/sec [4,212..4,272] → 4,229 ops/sec [4,180..4,368] ~ overlap (-0.5%)
Float64Array write 1,498 ops/sec [1,472..1,533] → 1,471 ops/sec [1,454..1,477] ~ overlap (-1.8%) 4,284 ops/sec [4,223..4,305] → 4,302 ops/sec [4,190..4,527] ~ overlap (+0.4%)
Float16Array read 1,531 ops/sec [1,517..1,575] → 1,567 ops/sec [1,545..1,600] ~ overlap (+2.4%) 4,989 ops/sec [4,872..4,997] → 5,305 ops/sec [5,296..5,321] 🟢 +6.3%
Float32Array read 1,557 ops/sec [1,546..1,572] → 1,582 ops/sec [1,576..1,641] 🟢 +1.6% 5,729 ops/sec [5,662..5,764] → 5,692 ops/sec [5,589..6,211] ~ overlap (-0.7%)
Float64Array read 1,613 ops/sec [1,605..1,666] → 1,591 ops/sec [1,578..1,633] ~ overlap (-1.3%) 5,738 ops/sec [5,654..5,778] → 5,628 ops/sec [5,545..5,840] ~ overlap (-1.9%)
fill(1.5) 22,551 ops/sec [22,158..23,048] → 22,185 ops/sec [21,421..22,857] ~ overlap (-1.6%) 24,167 ops/sec [24,041..24,364] → 24,653 ops/sec [24,462..24,828] 🟢 +2.0%
slice() 85,870 ops/sec [85,120..88,760] → 87,987 ops/sec [86,424..88,466] ~ overlap (+2.5%) 96,737 ops/sec [96,215..97,677] → 100,933 ops/sec [99,909..101,572] 🟢 +4.3%
map(x => x * 2) 2,580 ops/sec [2,539..2,668] → 2,633 ops/sec [2,608..2,663] ~ overlap (+2.1%) 3,927 ops/sec [3,823..3,981] → 4,194 ops/sec [4,083..4,306] 🟢 +6.8%
filter(x => x > 25) 2,769 ops/sec [2,753..2,788] → 2,866 ops/sec [2,854..2,870] 🟢 +3.5% 4,339 ops/sec [4,324..4,498] → 4,625 ops/sec [4,561..4,952] 🟢 +6.6%
reduce (sum) 2,686 ops/sec [2,652..2,739] → 2,712 ops/sec [2,674..2,726] ~ overlap (+0.9%) 3,604 ops/sec [3,555..3,727] → 3,866 ops/sec [3,802..4,012] 🟢 +7.3%
sort() 18,715 ops/sec [18,622..18,806] → 20,818 ops/sec [20,666..20,896] 🟢 +11.2% 9,091 ops/sec [9,039..9,141] → 18,004 ops/sec [17,893..18,324] 🟢 +98.0%
indexOf() 99,569 ops/sec [99,213..100,971] → 107,367 ops/sec [107,096..108,442] 🟢 +7.8% 64,604 ops/sec [64,138..65,241] → 115,520 ops/sec [114,731..115,722] 🟢 +78.8%
reverse() 110,263 ops/sec [107,636..111,301] → 112,235 ops/sec [111,741..112,923] 🟢 +1.8% 134,572 ops/sec [133,568..135,856] → 138,972 ops/sec [138,544..139,458] 🟢 +3.3%
toReversed() 51,245 ops/sec [50,981..51,861] → 54,516 ops/sec [53,242..55,696] 🟢 +6.4% 30,758 ops/sec [30,709..30,868] → 53,769 ops/sec [53,648..54,057] 🟢 +74.8%
toSorted() 737 ops/sec [730..741] → 819 ops/sec [817..824] 🟢 +11.1% 350 ops/sec [344..351] → 692 ops/sec [688..695] 🟢 +97.5%
create view over existing buffer 157,231 ops/sec [154,115..162,515] → 153,799 ops/sec [152,488..156,385] ~ overlap (-2.2%) 196,363 ops/sec [189,060..201,601] → 199,720 ops/sec [195,388..202,154] ~ overlap (+1.7%)
subarray() 188,277 ops/sec [187,684..189,046] → 180,790 ops/sec [179,232..184,424] 🔴 -4.0% 280,255 ops/sec [271,100..281,195] → 278,179 ops/sec [275,546..279,573] ~ overlap (-0.7%)
set() from array 209,744 ops/sec [208,420..211,813] → 209,071 ops/sec [199,593..212,907] ~ overlap (-0.3%) 295,822 ops/sec [290,802..305,001] → 304,773 ops/sec [301,582..305,797] ~ overlap (+3.0%)
for-of loop 2,376 ops/sec [2,330..2,398] → 2,382 ops/sec [2,372..2,395] ~ overlap (+0.2%) 6,867 ops/sec [6,836..7,017] → 7,689 ops/sec [7,664..7,991] 🟢 +12.0%
spread into array 9,146 ops/sec [9,025..9,255] → 8,995 ops/sec [8,827..9,296] ~ overlap (-1.7%) 38,483 ops/sec [37,817..38,830] → 39,115 ops/sec [38,954..39,838] 🟢 +1.6%
f16round(1.337) 260,290 ops/sec [253,687..265,584] → 260,814 ops/sec [252,472..267,169] ~ overlap (+0.2%) 307,452 ops/sec [305,253..309,621] → 309,734 ops/sec [307,099..312,821] ~ overlap (+0.7%)
f16round over 100 values 1,635 ops/sec [1,619..1,644] → 1,647 ops/sec [1,593..1,681] ~ overlap (+0.8%) 3,395 ops/sec [3,382..3,430] → 3,696 ops/sec [3,645..3,708] 🟢 +8.9%
for-of.js — Interp: 7 unch. · avg +0.4% · Bytecode: 7 unch. · avg +0.6%
Benchmark Interpreted Δ Bytecode Δ
for...of with 10-element array 21,013 ops/sec [20,823..21,433] → 21,562 ops/sec [21,273..21,769] ~ overlap (+2.6%) 97,586 ops/sec [96,316..102,446] → 96,534 ops/sec [95,609..98,177] ~ overlap (-1.1%)
for...of with 100-element array 2,428 ops/sec [2,374..2,432] → 2,445 ops/sec [2,426..2,493] ~ overlap (+0.7%) 11,537 ops/sec [11,292..11,821] → 11,635 ops/sec [11,368..11,922] ~ overlap (+0.8%)
for...of with string (10 chars) 15,122 ops/sec [15,006..15,312] → 14,889 ops/sec [14,646..15,102] ~ overlap (-1.5%) 37,439 ops/sec [37,234..37,714] → 37,170 ops/sec [36,561..37,566] ~ overlap (-0.7%)
for...of with Set (10 elements) 21,864 ops/sec [21,489..22,059] → 21,454 ops/sec [21,436..21,557] ~ overlap (-1.9%) 97,020 ops/sec [95,751..98,875] → 95,636 ops/sec [93,127..97,306] ~ overlap (-1.4%)
for...of with Map entries (10 entries) 14,167 ops/sec [14,038..14,337] → 14,346 ops/sec [14,187..14,461] ~ overlap (+1.3%) 16,730 ops/sec [16,639..16,986] → 17,178 ops/sec [16,909..17,553] ~ overlap (+2.7%)
for...of with destructuring 17,656 ops/sec [17,295..17,928] → 17,932 ops/sec [17,656..18,052] ~ overlap (+1.6%) 21,265 ops/sec [20,805..21,458] → 21,617 ops/sec [20,956..21,766] ~ overlap (+1.7%)
for-await-of with sync array 20,399 ops/sec [20,234..20,719] → 20,376 ops/sec [19,941..20,557] ~ overlap (-0.1%) 17,281 ops/sec [16,040..18,444] → 17,705 ops/sec [17,376..18,336] ~ overlap (+2.5%)
generators.js — Interp: 🟢 3, 1 unch. · avg +3.4% · Bytecode: 4 unch. · avg -0.8%
Benchmark Interpreted Δ Bytecode Δ
manual next over object generator 891 ops/sec [888..897] → 921 ops/sec [903..934] 🟢 +3.4% 1,308 ops/sec [1,279..1,323] → 1,296 ops/sec [1,248..1,308] ~ overlap (-1.0%)
for...of over object generator 1,445 ops/sec [1,429..1,468] → 1,488 ops/sec [1,467..1,516] ~ overlap (+3.0%) 2,223 ops/sec [2,178..2,239] → 2,171 ops/sec [2,131..2,228] ~ overlap (-2.3%)
yield delegation 1,478 ops/sec [1,476..1,484] → 1,530 ops/sec [1,524..1,540] 🟢 +3.5% 2,241 ops/sec [2,170..2,280] → 2,260 ops/sec [2,216..2,304] ~ overlap (+0.8%)
class generator method 1,450 ops/sec [1,423..1,468] → 1,503 ops/sec [1,468..1,537] 🟢 +3.7% 2,195 ops/sec [2,155..2,258] → 2,183 ops/sec [2,149..2,239] ~ overlap (-0.6%)
iterators.js — Interp: 🟢 8, 34 unch. · avg +1.0% · Bytecode: 🟢 6, 🔴 3, 33 unch. · avg +0.5%
Benchmark Interpreted Δ Bytecode Δ
Iterator.from({next}).toArray() — 20 elements 4,703 ops/sec [4,570..4,783] → 4,799 ops/sec [4,777..4,804] ~ overlap (+2.0%) 6,977 ops/sec [6,916..7,089] → 7,404 ops/sec [6,985..7,452] ~ overlap (+6.1%)
Iterator.from({next}).toArray() — 50 elements 1,987 ops/sec [1,968..1,989] → 2,007 ops/sec [1,959..2,014] ~ overlap (+1.0%) 3,157 ops/sec [3,107..3,208] → 3,195 ops/sec [3,154..3,222] ~ overlap (+1.2%)
spread pre-wrapped iterator — 20 elements 4,608 ops/sec [4,575..4,792] → 4,642 ops/sec [4,610..4,687] ~ overlap (+0.7%) 7,131 ops/sec [6,975..7,196] → 7,296 ops/sec [7,001..7,439] ~ overlap (+2.3%)
Iterator.from({next}).forEach — 50 elements 1,449 ops/sec [1,421..1,482] → 1,473 ops/sec [1,466..1,475] ~ overlap (+1.7%) 2,365 ops/sec [2,339..2,376] → 2,365 ops/sec [2,326..2,375] ~ overlap (+0.0%)
Iterator.from({next}).reduce — 50 elements 1,485 ops/sec [1,454..1,532] → 1,505 ops/sec [1,493..1,517] ~ overlap (+1.4%) 2,306 ops/sec [2,274..2,320] → 2,414 ops/sec [2,401..2,416] 🟢 +4.7%
wrap array iterator 74,656 ops/sec [73,029..75,072] → 75,603 ops/sec [74,805..76,272] ~ overlap (+1.3%) 86,898 ops/sec [84,573..87,775] → 89,253 ops/sec [87,206..90,677] ~ overlap (+2.7%)
wrap plain {next()} object 3,204 ops/sec [3,168..3,230] → 3,330 ops/sec [3,263..3,355] 🟢 +3.9% 4,984 ops/sec [4,800..5,065] → 5,113 ops/sec [5,083..5,188] 🟢 +2.6%
map + toArray (50 elements) 1,485 ops/sec [1,465..1,496] → 1,515 ops/sec [1,484..1,533] ~ overlap (+2.0%) 2,413 ops/sec [2,370..2,445] → 2,478 ops/sec [2,395..2,630] ~ overlap (+2.7%)
filter + toArray (50 elements) 1,451 ops/sec [1,434..1,469] → 1,461 ops/sec [1,448..1,481] ~ overlap (+0.7%) 2,455 ops/sec [2,438..2,477] → 2,508 ops/sec [2,481..2,559] 🟢 +2.2%
take(10) + toArray (50 element source) 8,933 ops/sec [8,896..8,954] → 9,172 ops/sec [9,056..9,242] 🟢 +2.7% 13,992 ops/sec [13,802..14,149] → 13,991 ops/sec [13,681..14,502] ~ overlap (-0.0%)
drop(40) + toArray (50 element source) 1,984 ops/sec [1,959..1,995] → 2,051 ops/sec [2,002..2,080] 🟢 +3.4% 3,119 ops/sec [3,005..3,139] → 3,371 ops/sec [3,232..3,388] 🟢 +8.1%
chained map + filter + take (100 element source) 2,793 ops/sec [2,777..2,811] → 2,867 ops/sec [2,839..2,907] 🟢 +2.6% 4,655 ops/sec [4,500..4,713] → 4,809 ops/sec [4,755..4,893] 🟢 +3.3%
some + every (50 elements) 828 ops/sec [826..833] → 867 ops/sec [852..886] 🟢 +4.6% 1,383 ops/sec [1,365..1,387] → 1,360 ops/sec [1,322..1,391] ~ overlap (-1.7%)
find (50 elements) 1,873 ops/sec [1,854..1,888] → 1,857 ops/sec [1,819..1,915] ~ overlap (-0.8%) 3,018 ops/sec [2,994..3,078] → 3,032 ops/sec [2,928..3,056] ~ overlap (+0.5%)
concat 2 arrays (10 + 10 elements) 71,501 ops/sec [69,861..72,357] → 70,646 ops/sec [69,357..73,066] ~ overlap (-1.2%) 83,872 ops/sec [82,564..86,768] → 81,774 ops/sec [80,416..83,884] ~ overlap (-2.5%)
concat 5 arrays (10 elements each) 42,414 ops/sec [41,929..42,614] → 42,805 ops/sec [41,774..42,945] ~ overlap (+0.9%) 49,935 ops/sec [48,534..50,158] → 48,698 ops/sec [47,992..52,161] ~ overlap (-2.5%)
concat 2 arrays (20 + 20 elements) 62,444 ops/sec [61,387..62,898] → 61,407 ops/sec [60,048..61,832] ~ overlap (-1.7%) 73,965 ops/sec [72,254..75,405] → 71,880 ops/sec [70,132..74,045] ~ overlap (-2.8%)
concat + filter + toArray (20 + 20 elements) 6,034 ops/sec [5,970..6,072] → 5,960 ops/sec [5,859..6,104] ~ overlap (-1.2%) 10,532 ops/sec [10,274..10,730] → 10,804 ops/sec [10,723..10,957] ~ overlap (+2.6%)
concat + map + take (20 + 20 elements, take 10) 19,274 ops/sec [18,545..20,018] → 19,168 ops/sec [18,621..19,427] ~ overlap (-0.6%) 29,978 ops/sec [29,399..30,478] → 30,033 ops/sec [29,241..30,491] ~ overlap (+0.2%)
concat Sets (15 + 15 elements) 72,906 ops/sec [71,530..73,350] → 71,498 ops/sec [71,116..72,020] ~ overlap (-1.9%) 79,571 ops/sec [78,350..80,378] → 79,224 ops/sec [79,056..80,089] ~ overlap (-0.4%)
concat strings (13 + 13 characters) 49,541 ops/sec [48,732..50,449] → 47,804 ops/sec [47,401..49,031] ~ overlap (-3.5%) 53,103 ops/sec [52,220..53,640] → 52,600 ops/sec [51,373..53,815] ~ overlap (-0.9%)
zip 2 arrays (10 + 10 elements) 28,271 ops/sec [28,051..28,955] → 28,622 ops/sec [27,874..29,030] ~ overlap (+1.2%) 30,209 ops/sec [29,547..30,444] → 29,880 ops/sec [29,285..30,663] ~ overlap (-1.1%)
zip 3 arrays (10 elements each) 26,257 ops/sec [25,642..26,636] → 26,224 ops/sec [25,939..26,940] ~ overlap (-0.1%) 27,718 ops/sec [27,498..28,010] → 27,573 ops/sec [27,163..28,445] ~ overlap (-0.5%)
zip 2 arrays (20 + 20 elements) 18,838 ops/sec [18,706..19,133] → 19,163 ops/sec [18,942..19,363] ~ overlap (+1.7%) 19,684 ops/sec [19,414..20,065] → 19,570 ops/sec [19,221..20,145] ~ overlap (-0.6%)
zip 2 arrays (50 + 50 elements) 9,490 ops/sec [9,190..9,615] → 9,684 ops/sec [9,202..9,864] ~ overlap (+2.0%) 10,103 ops/sec [10,010..10,167] → 9,873 ops/sec [9,733..9,970] 🔴 -2.3%
zip shortest mode (20 + 10 elements) 28,082 ops/sec [27,443..28,614] → 28,534 ops/sec [27,381..28,746] ~ overlap (+1.6%) 30,149 ops/sec [29,846..30,481] → 30,117 ops/sec [29,221..30,599] ~ overlap (-0.1%)
zip longest mode (10 + 20 elements) 16,591 ops/sec [16,304..16,757] → 17,076 ops/sec [16,669..17,437] ~ overlap (+2.9%) 17,912 ops/sec [17,682..18,436] → 17,338 ops/sec [17,168..17,422] 🔴 -3.2%
zip strict mode (20 + 20 elements) 18,246 ops/sec [17,730..18,555] → 19,061 ops/sec [18,929..19,215] 🟢 +4.5% 18,816 ops/sec [18,654..19,269] → 18,421 ops/sec [18,236..18,657] ~ overlap (-2.1%)
zip + map + toArray (20 + 20 elements) 7,563 ops/sec [7,527..7,648] → 7,657 ops/sec [7,635..7,705] ~ overlap (+1.2%) 6,029 ops/sec [5,934..6,121] → 5,888 ops/sec [5,856..5,926] 🔴 -2.3%
zip + filter + toArray (20 + 20 elements) 7,286 ops/sec [7,201..7,382] → 7,365 ops/sec [7,348..7,369] ~ overlap (+1.1%) 6,149 ops/sec [6,091..6,159] → 6,033 ops/sec [5,897..6,162] ~ overlap (-1.9%)
zip Sets (15 + 15 elements) 23,678 ops/sec [23,495..23,756] → 24,168 ops/sec [23,790..24,324] 🟢 +2.1% 24,679 ops/sec [24,549..24,778] → 24,356 ops/sec [24,186..24,957] ~ overlap (-1.3%)
zipKeyed 2 keys (10 elements each) 29,535 ops/sec [29,021..29,701] → 29,590 ops/sec [29,287..30,163] ~ overlap (+0.2%) 31,301 ops/sec [30,733..31,597] → 30,685 ops/sec [30,235..31,312] ~ overlap (-2.0%)
zipKeyed 3 keys (20 elements each) 14,875 ops/sec [14,401..15,126] → 15,027 ops/sec [14,834..15,240] ~ overlap (+1.0%) 15,658 ops/sec [15,448..15,898] → 15,926 ops/sec [15,527..16,397] ~ overlap (+1.7%)
zipKeyed longest mode (10 + 20 elements) 17,208 ops/sec [16,913..17,381] → 17,269 ops/sec [17,052..17,422] ~ overlap (+0.4%) 17,497 ops/sec [17,290..18,092] → 17,600 ops/sec [17,373..18,032] ~ overlap (+0.6%)
zipKeyed strict mode (20 + 20 elements) 18,009 ops/sec [17,923..18,057] → 18,349 ops/sec [18,178..18,668] 🟢 +1.9% 18,489 ops/sec [18,296..18,580] → 18,480 ops/sec [17,969..18,794] ~ overlap (-0.0%)
zipKeyed + filter + map (20 elements) 5,512 ops/sec [5,419..5,545] → 5,617 ops/sec [5,517..5,689] ~ overlap (+1.9%) 7,341 ops/sec [7,289..7,398] → 7,842 ops/sec [7,677..7,938] 🟢 +6.8%
array.values().map().filter().toArray() 2,869 ops/sec [2,802..2,895] → 2,869 ops/sec [2,754..2,906] ~ overlap (+0.0%) 4,939 ops/sec [4,904..4,982] → 5,081 ops/sec [4,942..5,254] ~ overlap (+2.9%)
array.values().take(5).toArray() 98,640 ops/sec [96,251..100,699] → 97,094 ops/sec [95,861..97,835] ~ overlap (-1.6%) 121,585 ops/sec [119,480..123,572] → 119,314 ops/sec [116,161..121,520] ~ overlap (-1.9%)
array.values().drop(45).toArray() 80,918 ops/sec [80,095..81,863] → 79,232 ops/sec [77,595..80,228] ~ overlap (-2.1%) 94,460 ops/sec [91,754..95,961] → 94,816 ops/sec [93,302..95,296] ~ overlap (+0.4%)
map.entries() chained helpers 4,207 ops/sec [4,110..4,307] → 4,206 ops/sec [4,095..4,367] ~ overlap (-0.0%) 3,183 ops/sec [3,120..3,218] → 3,178 ops/sec [3,117..3,199] ~ overlap (-0.2%)
set.values() chained helpers 6,246 ops/sec [6,185..6,362] → 6,298 ops/sec [6,181..6,383] ~ overlap (+0.8%) 10,887 ops/sec [10,586..11,407] → 10,869 ops/sec [10,754..10,996] ~ overlap (-0.2%)
string iterator map + toArray 5,160 ops/sec [5,141..5,343] → 5,355 ops/sec [5,331..5,371] ~ overlap (+3.8%) 6,832 ops/sec [6,776..6,869] → 6,715 ops/sec [6,657..6,781] ~ overlap (-1.7%)
json.js — Interp: 🟢 8, 12 unch. · avg +1.9% · Bytecode: 🟢 1, 19 unch. · avg +0.6%
Benchmark Interpreted Δ Bytecode Δ
parse simple object 70,949 ops/sec [70,441..71,849] → 72,076 ops/sec [70,877..73,256] ~ overlap (+1.6%) 83,005 ops/sec [81,712..86,205] → 83,774 ops/sec [82,924..84,368] ~ overlap (+0.9%)
parse nested object 46,957 ops/sec [46,811..47,052] → 48,003 ops/sec [47,597..48,542] 🟢 +2.2% 55,431 ops/sec [54,156..57,372] → 53,962 ops/sec [53,521..54,986] ~ overlap (-2.6%)
parse array of objects 27,791 ops/sec [27,601..28,163] → 28,575 ops/sec [28,182..29,279] 🟢 +2.8% 32,288 ops/sec [31,586..33,643] → 31,941 ops/sec [31,800..32,363] ~ overlap (-1.1%)
parse large flat object 29,261 ops/sec [28,850..30,301] → 32,943 ops/sec [32,696..33,177] 🟢 +12.6% 33,886 ops/sec [33,675..35,048] → 34,431 ops/sec [33,626..34,641] ~ overlap (+1.6%)
parse mixed types 34,353 ops/sec [33,846..35,416] → 36,679 ops/sec [36,245..37,055] 🟢 +6.8% 40,852 ops/sec [40,019..41,960] → 41,025 ops/sec [40,715..41,461] ~ overlap (+0.4%)
stringify simple object 78,553 ops/sec [75,324..79,391] → 77,872 ops/sec [77,424..79,774] ~ overlap (-0.9%) 85,307 ops/sec [84,237..86,835] → 86,147 ops/sec [85,205..87,646] ~ overlap (+1.0%)
stringify nested object 45,570 ops/sec [44,729..45,973] → 47,125 ops/sec [46,256..48,219] 🟢 +3.4% 47,365 ops/sec [47,163..48,886] → 48,881 ops/sec [48,664..49,628] ~ overlap (+3.2%)
stringify array of objects 19,106 ops/sec [18,728..19,229] → 19,978 ops/sec [18,471..20,773] ~ overlap (+4.6%) 21,248 ops/sec [20,126..21,998] → 21,338 ops/sec [21,132..22,790] ~ overlap (+0.4%)
stringify mixed types 28,521 ops/sec [28,507..28,532] → 28,870 ops/sec [28,745..29,129] 🟢 +1.2% 32,115 ops/sec [31,457..33,061] → 32,175 ops/sec [31,976..32,469] ~ overlap (+0.2%)
reviver doubles numbers 13,808 ops/sec [13,577..13,949] → 14,197 ops/sec [13,940..14,430] ~ overlap (+2.8%) 20,395 ops/sec [19,688..21,146] → 20,378 ops/sec [19,995..20,433] ~ overlap (-0.1%)
reviver filters properties 12,100 ops/sec [11,480..12,218] → 11,809 ops/sec [11,656..12,058] ~ overlap (-2.4%) 17,919 ops/sec [17,575..18,102] → 18,134 ops/sec [18,028..18,268] ~ overlap (+1.2%)
reviver on nested object 16,281 ops/sec [16,223..16,444] → 16,538 ops/sec [16,281..16,677] ~ overlap (+1.6%) 21,987 ops/sec [21,815..22,508] → 22,321 ops/sec [21,944..22,417] ~ overlap (+1.5%)
reviver on array 8,550 ops/sec [8,400..8,639] → 8,679 ops/sec [8,521..8,745] ~ overlap (+1.5%) 12,484 ops/sec [12,146..12,547] → 12,697 ops/sec [12,544..12,907] ~ overlap (+1.7%)
replacer function doubles numbers 16,195 ops/sec [16,127..16,295] → 16,043 ops/sec [15,822..16,203] ~ overlap (-0.9%) 23,990 ops/sec [23,668..24,677] → 24,617 ops/sec [24,293..24,900] ~ overlap (+2.6%)
replacer function excludes properties 22,494 ops/sec [21,448..22,801] → 21,372 ops/sec [20,662..21,633] ~ overlap (-5.0%) 29,199 ops/sec [28,798..29,963] → 29,721 ops/sec [29,253..30,099] ~ overlap (+1.8%)
array replacer (allowlist) 46,664 ops/sec [46,180..47,518] → 48,270 ops/sec [47,558..49,451] 🟢 +3.4% 50,811 ops/sec [49,632..52,029] → 51,785 ops/sec [50,776..52,322] ~ overlap (+1.9%)
stringify with 2-space indent 38,402 ops/sec [37,290..40,053] → 38,374 ops/sec [37,272..39,353] ~ overlap (-0.1%) 42,770 ops/sec [41,951..42,891] → 43,378 ops/sec [43,237..43,912] 🟢 +1.4%
stringify with tab indent 38,076 ops/sec [37,319..38,515] → 38,077 ops/sec [37,701..40,033] ~ overlap (+0.0%) 44,150 ops/sec [43,597..44,624] → 42,818 ops/sec [42,081..43,716] ~ overlap (-3.0%)
parse then stringify 23,479 ops/sec [22,945..24,019] → 23,566 ops/sec [23,018..23,958] ~ overlap (+0.4%) 27,987 ops/sec [27,877..28,056] → 27,636 ops/sec [27,253..28,043] ~ overlap (-1.3%)
stringify then parse 13,505 ops/sec [13,438..13,517] → 13,703 ops/sec [13,641..13,772] 🟢 +1.5% 15,672 ops/sec [14,744..16,463] → 15,659 ops/sec [15,643..15,770] ~ overlap (-0.1%)
jsx.jsx — Interp: 🔴 5, 16 unch. · avg -2.0% · Bytecode: 🟢 2, 🔴 2, 17 unch. · avg -0.8%
Benchmark Interpreted Δ Bytecode Δ
simple element 92,167 ops/sec [90,684..95,814] → 92,913 ops/sec [91,915..93,637] ~ overlap (+0.8%) 157,848 ops/sec [157,214..159,441] → 156,698 ops/sec [152,051..158,813] ~ overlap (-0.7%)
self-closing element 96,400 ops/sec [92,944..99,574] → 95,082 ops/sec [94,196..95,315] ~ overlap (-1.4%) 173,316 ops/sec [172,598..175,703] → 174,490 ops/sec [173,636..177,321] ~ overlap (+0.7%)
element with string attribute 81,606 ops/sec [80,022..82,595] → 83,564 ops/sec [82,127..83,762] ~ overlap (+2.4%) 120,584 ops/sec [118,127..127,383] → 125,603 ops/sec [124,662..126,574] ~ overlap (+4.2%)
element with multiple attributes 73,477 ops/sec [72,362..75,164] → 72,040 ops/sec [69,867..73,983] ~ overlap (-2.0%) 97,526 ops/sec [96,068..107,326] → 95,141 ops/sec [94,003..95,821] 🔴 -2.4%
element with expression attribute 76,899 ops/sec [76,763..77,701] → 76,349 ops/sec [74,192..78,875] ~ overlap (-0.7%) 137,933 ops/sec [136,015..139,522] → 125,940 ops/sec [125,379..127,168] 🔴 -8.7%
text child 94,094 ops/sec [92,361..95,634] → 94,365 ops/sec [91,986..94,837] ~ overlap (+0.3%) 164,313 ops/sec [161,920..169,924] → 155,070 ops/sec [149,260..163,111] ~ overlap (-5.6%)
expression child 92,846 ops/sec [91,178..95,158] → 91,082 ops/sec [90,489..91,763] ~ overlap (-1.9%) 167,732 ops/sec [166,334..169,054] → 156,557 ops/sec [154,483..168,355] ~ overlap (-6.7%)
mixed text and expression 87,550 ops/sec [86,418..89,564] → 85,930 ops/sec [84,021..86,893] ~ overlap (-1.9%) 146,647 ops/sec [128,921..147,831] → 136,208 ops/sec [133,374..140,875] ~ overlap (-7.1%)
nested elements (3 levels) 37,045 ops/sec [36,451..37,325] → 36,093 ops/sec [35,421..36,550] ~ overlap (-2.6%) 61,935 ops/sec [57,984..64,441] → 60,624 ops/sec [60,473..62,254] ~ overlap (-2.1%)
sibling children 27,638 ops/sec [26,987..28,000] → 26,449 ops/sec [26,076..27,008] ~ overlap (-4.3%) 43,607 ops/sec [42,814..43,943] → 43,779 ops/sec [42,840..44,096] ~ overlap (+0.4%)
component element 71,196 ops/sec [70,058..72,749] → 69,968 ops/sec [69,458..71,085] ~ overlap (-1.7%) 114,917 ops/sec [114,504..116,501] → 113,775 ops/sec [111,747..115,951] ~ overlap (-1.0%)
component with children 44,724 ops/sec [44,194..45,310] → 43,122 ops/sec [42,396..43,328] 🔴 -3.6% 68,961 ops/sec [68,104..69,962] → 69,473 ops/sec [68,353..69,838] ~ overlap (+0.7%)
dotted component 62,286 ops/sec [61,844..62,390] → 60,493 ops/sec [60,190..60,639] 🔴 -2.9% 88,973 ops/sec [85,656..89,668] → 86,951 ops/sec [85,538..91,449] ~ overlap (-2.3%)
empty fragment 97,167 ops/sec [96,353..98,875] → 96,114 ops/sec [95,612..96,851] ~ overlap (-1.1%) 187,794 ops/sec [185,518..190,713] → 190,498 ops/sec [185,937..193,555] ~ overlap (+1.4%)
fragment with children 27,487 ops/sec [26,285..27,639] → 27,292 ops/sec [26,843..27,492] ~ overlap (-0.7%) 44,354 ops/sec [43,443..45,026] → 45,583 ops/sec [43,704..46,428] ~ overlap (+2.8%)
spread attributes 52,538 ops/sec [51,334..53,321] → 51,458 ops/sec [51,158..51,591] ~ overlap (-2.1%) 68,800 ops/sec [68,561..68,933] → 67,746 ops/sec [67,001..68,816] ~ overlap (-1.5%)
spread with overrides 47,917 ops/sec [47,271..48,665] → 45,700 ops/sec [45,470..46,189] 🔴 -4.6% 59,610 ops/sec [57,866..60,820] → 59,631 ops/sec [57,754..60,219] ~ overlap (+0.0%)
shorthand props 76,680 ops/sec [74,402..79,508] → 73,969 ops/sec [73,226..74,586] ~ overlap (-3.5%) 111,826 ops/sec [110,038..113,447] → 118,097 ops/sec [117,375..118,370] 🟢 +5.6%
nav bar structure 13,447 ops/sec [12,854..14,142] → 12,898 ops/sec [12,777..12,982] ~ overlap (-4.1%) 20,342 ops/sec [19,761..20,482] → 20,689 ops/sec [20,586..20,866] 🟢 +1.7%
card component tree 15,777 ops/sec [15,602..15,882] → 15,154 ops/sec [15,098..15,219] 🔴 -4.0% 22,430 ops/sec [22,032..22,952] → 22,827 ops/sec [22,799..22,835] ~ overlap (+1.8%)
10 list items via Array.from 6,965 ops/sec [6,931..7,000] → 6,792 ops/sec [6,750..6,858] 🔴 -2.5% 9,764 ops/sec [9,629..10,106] → 9,986 ops/sec [9,898..10,039] ~ overlap (+2.3%)
modules.js — Interp: 🟢 3, 6 unch. · avg +1.9% · Bytecode: 🟢 2, 🔴 1, 6 unch. · avg +0.9%
Benchmark Interpreted Δ Bytecode Δ
call imported function 160,106 ops/sec [158,179..161,170] → 160,881 ops/sec [151,592..167,004] ~ overlap (+0.5%) 769,364 ops/sec [767,197..776,668] → 785,183 ops/sec [779,380..787,032] 🟢 +2.1%
call two imported functions 91,269 ops/sec [90,401..92,346] → 91,794 ops/sec [91,002..92,706] ~ overlap (+0.6%) 517,083 ops/sec [513,898..522,705] → 505,016 ops/sec [499,991..507,876] 🔴 -2.3%
read imported constant 532,609 ops/sec [522,365..546,642] → 533,644 ops/sec [520,736..541,353] ~ overlap (+0.2%) 2,000,390 ops/sec [1,976,536..2,031,524] → 2,019,488 ops/sec [1,996,831..2,046,291] ~ overlap (+1.0%)
read imported string 531,782 ops/sec [508,022..537,650] → 543,276 ops/sec [530,250..561,377] ~ overlap (+2.2%) 2,002,004 ops/sec [1,999,454..2,008,104] → 2,012,788 ops/sec [2,006,628..2,019,516] ~ overlap (+0.5%)
read JSON string property 531,689 ops/sec [523,159..545,674] → 539,552 ops/sec [512,529..548,369] ~ overlap (+1.5%) 1,998,781 ops/sec [1,979,259..2,013,500] → 2,017,568 ops/sec [2,006,465..2,032,973] ~ overlap (+0.9%)
read JSON number property 516,419 ops/sec [501,228..520,857] → 538,011 ops/sec [524,116..553,183] 🟢 +4.2% 1,984,110 ops/sec [1,973,149..2,003,786] → 2,013,351 ops/sec [1,997,667..2,025,204] ~ overlap (+1.5%)
read JSON boolean property 519,066 ops/sec [510,286..522,543] → 534,958 ops/sec [524,796..569,435] 🟢 +3.1% 1,960,494 ops/sec [1,936,272..1,968,992] → 2,003,632 ops/sec [1,990,785..2,007,811] 🟢 +2.2%
read JSON array property 522,030 ops/sec [519,551..524,521] → 539,348 ops/sec [531,761..553,428] 🟢 +3.3% 1,973,432 ops/sec [1,968,353..1,978,198] → 1,984,405 ops/sec [1,966,514..2,047,983] ~ overlap (+0.6%)
read multiple JSON properties 322,181 ops/sec [316,052..331,584] → 328,530 ops/sec [320,043..347,061] ~ overlap (+2.0%) 1,636,927 ops/sec [1,617,474..1,655,738] → 1,658,525 ops/sec [1,635,730..1,668,355] ~ overlap (+1.3%)
numbers.js — Interp: 11 unch. · avg +1.4% · Bytecode: 🟢 2, 🔴 2, 7 unch. · avg -0.6%
Benchmark Interpreted Δ Bytecode Δ
integer arithmetic 170,668 ops/sec [165,797..174,772] → 173,743 ops/sec [168,724..176,737] ~ overlap (+1.8%) 709,849 ops/sec [705,492..723,001] → 710,705 ops/sec [686,658..723,165] ~ overlap (+0.1%)
floating point arithmetic 195,042 ops/sec [192,526..203,742] → 203,116 ops/sec [196,854..205,709] ~ overlap (+4.1%) 437,394 ops/sec [435,379..441,541] → 431,644 ops/sec [429,326..434,144] 🔴 -1.3%
number coercion 73,909 ops/sec [72,195..74,495] → 73,785 ops/sec [72,878..75,715] ~ overlap (-0.2%) 102,808 ops/sec [102,414..103,175] → 101,104 ops/sec [97,559..103,073] ~ overlap (-1.7%)
toFixed 49,908 ops/sec [49,223..50,713] → 50,606 ops/sec [50,377..51,920] ~ overlap (+1.4%) 60,279 ops/sec [59,715..60,567] → 62,159 ops/sec [61,327..62,518] 🟢 +3.1%
toString 64,092 ops/sec [63,829..64,601] → 64,957 ops/sec [62,934..66,496] ~ overlap (+1.4%) 83,830 ops/sec [83,645..84,675] → 84,292 ops/sec [82,021..85,266] ~ overlap (+0.6%)
valueOf 99,284 ops/sec [95,862..99,995] → 100,736 ops/sec [98,697..103,224] ~ overlap (+1.5%) 127,468 ops/sec [126,408..129,205] → 131,057 ops/sec [129,862..133,728] 🟢 +2.8%
toPrecision 42,326 ops/sec [42,118..42,917] → 42,808 ops/sec [42,045..44,454] ~ overlap (+1.1%) 50,011 ops/sec [49,647..50,418] → 49,076 ops/sec [48,630..50,363] ~ overlap (-1.9%)
Number.isNaN 118,255 ops/sec [116,604..119,072] → 118,060 ops/sec [115,407..120,254] ~ overlap (-0.2%) 142,319 ops/sec [141,225..142,870] → 141,412 ops/sec [136,360..142,042] ~ overlap (-0.6%)
Number.isFinite 114,751 ops/sec [113,880..116,924] → 115,966 ops/sec [112,594..118,576] ~ overlap (+1.1%) 137,216 ops/sec [136,393..138,223] → 135,529 ops/sec [130,105..139,903] ~ overlap (-1.2%)
Number.isInteger 118,122 ops/sec [115,351..120,182] → 118,878 ops/sec [116,979..121,673] ~ overlap (+0.6%) 148,155 ops/sec [147,556..149,453] → 144,311 ops/sec [142,636..148,197] ~ overlap (-2.6%)
Number.parseInt and parseFloat 96,504 ops/sec [95,301..97,839] → 98,903 ops/sec [96,332..100,282] ~ overlap (+2.5%) 112,176 ops/sec [111,662..112,432] → 108,157 ops/sec [107,070..108,732] 🔴 -3.6%
objects.js — Interp: 🟢 3, 4 unch. · avg +1.7% · Bytecode: 🟢 2, 🔴 1, 4 unch. · avg +0.1%
Benchmark Interpreted Δ Bytecode Δ
create simple object 210,613 ops/sec [203,990..216,275] → 216,243 ops/sec [210,994..220,542] ~ overlap (+2.7%) 278,203 ops/sec [267,047..286,842] → 289,903 ops/sec [286,923..293,116] 🟢 +4.2%
create nested object 111,827 ops/sec [110,715..114,057] → 115,261 ops/sec [114,342..116,735] 🟢 +3.1% 122,209 ops/sec [118,196..123,077] → 124,708 ops/sec [123,227..125,930] 🟢 +2.0%
create 50 objects via Array.from 4,061 ops/sec [4,017..4,186] → 4,093 ops/sec [3,960..4,191] ~ overlap (+0.8%) 4,875 ops/sec [4,836..4,993] → 4,785 ops/sec [4,749..4,827] 🔴 -1.8%
property read 195,376 ops/sec [191,360..197,414] → 202,753 ops/sec [198,077..205,201] 🟢 +3.8% 339,442 ops/sec [327,551..364,392] → 335,174 ops/sec [330,942..345,478] ~ overlap (-1.3%)
Object.keys 124,536 ops/sec [120,913..125,684] → 124,314 ops/sec [123,374..124,611] ~ overlap (-0.2%) 150,235 ops/sec [147,023..151,013] → 151,342 ops/sec [149,215..153,768] ~ overlap (+0.7%)
Object.entries 48,753 ops/sec [48,056..49,146] → 49,684 ops/sec [49,421..50,788] 🟢 +1.9% 57,426 ops/sec [55,983..58,291] → 56,488 ops/sec [56,204..57,749] ~ overlap (-1.6%)
spread operator 89,358 ops/sec [89,015..89,474] → 89,134 ops/sec [88,468..89,601] ~ overlap (-0.2%) 110,682 ops/sec [108,650..111,291] → 109,029 ops/sec [107,355..110,093] ~ overlap (-1.5%)
promises.js — Interp: 12 unch. · avg -0.6% · Bytecode: 🟢 2, 10 unch. · avg +1.2%
Benchmark Interpreted Δ Bytecode Δ
Promise.resolve(value) 207,956 ops/sec [202,313..213,525] → 208,165 ops/sec [204,838..211,367] ~ overlap (+0.1%) 269,062 ops/sec [264,177..272,784] → 266,071 ops/sec [262,004..268,430] ~ overlap (-1.1%)
new Promise(resolve => resolve(value)) 81,442 ops/sec [79,394..81,963] → 80,491 ops/sec [79,702..81,045] ~ overlap (-1.2%) 112,960 ops/sec [111,159..114,989] → 117,349 ops/sec [113,267..118,332] ~ overlap (+3.9%)
Promise.reject(reason) 209,750 ops/sec [207,656..211,317] → 210,963 ops/sec [209,851..213,217] ~ overlap (+0.6%) 254,681 ops/sec [247,759..260,916] → 249,077 ops/sec [245,719..252,661] ~ overlap (-2.2%)
resolve + then (1 handler) 76,976 ops/sec [75,358..78,493] → 76,034 ops/sec [75,481..77,595] ~ overlap (-1.2%) 106,687 ops/sec [103,627..111,109] → 104,936 ops/sec [103,920..107,745] ~ overlap (-1.6%)
resolve + then chain (3 deep) 32,017 ops/sec [31,147..32,229] → 31,459 ops/sec [30,881..32,092] ~ overlap (-1.7%) 43,138 ops/sec [42,020..43,927] → 43,788 ops/sec [42,999..46,082] ~ overlap (+1.5%)
resolve + then chain (10 deep) 10,535 ops/sec [10,407..10,750] → 10,391 ops/sec [10,282..10,437] ~ overlap (-1.4%) 13,876 ops/sec [13,690..14,089] → 14,492 ops/sec [14,155..14,569] 🟢 +4.4%
reject + catch + then 46,308 ops/sec [45,314..46,670] → 45,714 ops/sec [45,377..47,173] ~ overlap (-1.3%) 58,087 ops/sec [57,792..58,184] → 58,600 ops/sec [57,658..60,416] ~ overlap (+0.9%)
resolve + finally + then 39,827 ops/sec [39,514..40,485] → 39,990 ops/sec [39,178..40,495] ~ overlap (+0.4%) 48,273 ops/sec [47,456..49,098] → 50,537 ops/sec [50,119..51,056] 🟢 +4.7%
Promise.all (5 resolved) 15,991 ops/sec [15,384..16,504] → 15,972 ops/sec [15,637..16,095] ~ overlap (-0.1%) 16,988 ops/sec [16,953..17,018] → 17,163 ops/sec [16,923..17,624] ~ overlap (+1.0%)
Promise.race (5 resolved) 16,448 ops/sec [16,270..16,986] → 16,681 ops/sec [16,510..17,063] ~ overlap (+1.4%) 18,160 ops/sec [17,746..18,384] → 18,463 ops/sec [18,067..18,687] ~ overlap (+1.7%)
Promise.allSettled (5 mixed) 13,628 ops/sec [13,467..13,883] → 13,600 ops/sec [13,438..14,116] ~ overlap (-0.2%) 14,499 ops/sec [14,381..14,746] → 14,476 ops/sec [14,366..14,913] ~ overlap (-0.2%)
Promise.any (5 mixed) 16,301 ops/sec [15,986..16,520] → 15,875 ops/sec [15,520..16,374] ~ overlap (-2.6%) 17,059 ops/sec [16,875..17,694] → 17,343 ops/sec [16,990..17,627] ~ overlap (+1.7%)
regexp.js — Interp: 🟢 1, 10 unch. · avg +1.1% · Bytecode: 11 unch. · avg +0.7%
Benchmark Interpreted Δ Bytecode Δ
regex literal creation 72,146 ops/sec [71,293..73,052] → 71,570 ops/sec [70,662..72,342] ~ overlap (-0.8%) 69,663 ops/sec [67,737..70,326] → 70,471 ops/sec [69,680..70,790] ~ overlap (+1.2%)
new RegExp(pattern, flags) 61,883 ops/sec [61,197..62,877] → 62,838 ops/sec [62,426..63,495] ~ overlap (+1.5%) 68,501 ops/sec [68,117..69,409] → 69,484 ops/sec [68,501..70,124] ~ overlap (+1.4%)
RegExp(existingRegex) returns the same regex 257,310 ops/sec [256,366..258,333] → 261,864 ops/sec [257,960..263,714] ~ overlap (+1.8%) 454,066 ops/sec [450,936..456,056] → 449,941 ops/sec [438,935..462,212] ~ overlap (-0.9%)
test() on a global regex 66,248 ops/sec [64,557..67,098] → 67,030 ops/sec [66,520..67,410] ~ overlap (+1.2%) 83,784 ops/sec [83,284..84,452] → 84,186 ops/sec [83,890..86,506] ~ overlap (+0.5%)
exec() with capture groups 56,269 ops/sec [55,644..56,794] → 56,104 ops/sec [55,246..57,895] ~ overlap (-0.3%) 69,932 ops/sec [69,264..71,571] → 70,845 ops/sec [69,744..72,485] ~ overlap (+1.3%)
toString() 192,759 ops/sec [191,506..193,727] → 194,393 ops/sec [191,513..198,963] ~ overlap (+0.8%) 302,605 ops/sec [300,763..303,868] → 304,456 ops/sec [297,130..311,882] ~ overlap (+0.6%)
match() with global regex 19,491 ops/sec [18,467..19,609] → 19,842 ops/sec [19,514..20,023] ~ overlap (+1.8%) 20,766 ops/sec [20,611..21,158] → 20,915 ops/sec [20,531..21,670] ~ overlap (+0.7%)
matchAll() with capture groups 10,069 ops/sec [9,897..10,130] → 10,092 ops/sec [10,035..10,254] ~ overlap (+0.2%) 13,117 ops/sec [13,028..13,298] → 13,235 ops/sec [12,522..13,459] ~ overlap (+0.9%)
replace() with global regex 19,164 ops/sec [18,800..19,429] → 19,541 ops/sec [19,343..19,728] ~ overlap (+2.0%) 20,232 ops/sec [19,886..20,452] → 20,226 ops/sec [19,894..21,128] ~ overlap (-0.0%)
search() with regex 38,715 ops/sec [38,357..38,839] → 39,835 ops/sec [39,776..40,061] 🟢 +2.9% 40,050 ops/sec [39,157..40,484] → 40,664 ops/sec [40,183..41,359] ~ overlap (+1.5%)
split() with regex separator 19,652 ops/sec [19,574..19,971] → 19,909 ops/sec [19,446..20,348] ~ overlap (+1.3%) 20,757 ops/sec [20,502..21,002] → 20,911 ops/sec [20,630..20,967] ~ overlap (+0.7%)
strings.js — Interp: 🟢 1, 🔴 1, 17 unch. · avg +0.3% · Bytecode: 🔴 10, 9 unch. · avg -2.8%
Benchmark Interpreted Δ Bytecode Δ
string concatenation 151,372 ops/sec [149,240..152,684] → 152,707 ops/sec [150,509..154,468] ~ overlap (+0.9%) 128,057 ops/sec [127,608..128,696] → 125,681 ops/sec [123,820..128,035] ~ overlap (-1.9%)
template literal 299,425 ops/sec [294,411..301,761] → 302,468 ops/sec [301,564..306,338] ~ overlap (+1.0%) 224,523 ops/sec [223,190..225,922] → 219,000 ops/sec [217,298..221,289] 🔴 -2.5%
string repeat 176,011 ops/sec [174,616..177,199] → 171,706 ops/sec [165,248..176,057] ~ overlap (-2.4%) 227,280 ops/sec [220,344..232,885] → 217,851 ops/sec [215,893..218,188] 🔴 -4.1%
split and join 63,208 ops/sec [60,864..64,780] → 61,789 ops/sec [60,505..62,484] ~ overlap (-2.2%) 75,426 ops/sec [73,322..75,872] → 73,779 ops/sec [73,074..74,515] ~ overlap (-2.2%)
indexOf and includes 73,480 ops/sec [72,573..74,584] → 71,924 ops/sec [70,826..72,512] 🔴 -2.1% 88,908 ops/sec [87,327..89,537] → 87,220 ops/sec [86,388..88,539] ~ overlap (-1.9%)
toUpperCase and toLowerCase 88,465 ops/sec [86,513..89,107] → 86,751 ops/sec [86,141..87,722] ~ overlap (-1.9%) 115,907 ops/sec [112,252..119,418] → 114,120 ops/sec [111,673..114,979] ~ overlap (-1.5%)
slice and substring 67,721 ops/sec [67,407..69,339] → 67,495 ops/sec [65,505..68,726] ~ overlap (-0.3%) 95,846 ops/sec [94,657..96,655] → 91,471 ops/sec [90,083..94,424] 🔴 -4.6%
trim operations 78,976 ops/sec [77,708..79,538] → 80,540 ops/sec [77,370..83,722] ~ overlap (+2.0%) 108,601 ops/sec [106,878..111,315] → 103,050 ops/sec [99,747..110,615] ~ overlap (-5.1%)
replace and replaceAll 81,850 ops/sec [80,304..82,066] → 83,910 ops/sec [81,218..84,394] ~ overlap (+2.5%) 95,468 ops/sec [94,547..98,494] → 92,993 ops/sec [91,809..93,908] 🔴 -2.6%
startsWith and endsWith 59,687 ops/sec [59,122..63,100] → 61,543 ops/sec [59,956..63,697] ~ overlap (+3.1%) 71,921 ops/sec [71,226..72,963] → 70,976 ops/sec [69,873..71,519] ~ overlap (-1.3%)
padStart and padEnd 88,652 ops/sec [87,362..89,512] → 90,335 ops/sec [88,244..91,613] ~ overlap (+1.9%) 110,991 ops/sec [109,884..113,319] → 104,533 ops/sec [102,036..106,890] 🔴 -5.8%
identity tag, no substitutions 166,660 ops/sec [165,210..169,203] → 172,793 ops/sec [171,621..177,343] 🟢 +3.7% 632,929 ops/sec [623,890..642,281] → 646,536 ops/sec [639,690..650,264] ~ overlap (+2.1%)
tag with 1 substitution 36,091 ops/sec [35,738..36,465] → 35,769 ops/sec [35,374..36,287] ~ overlap (-0.9%) 55,574 ops/sec [55,260..56,582] → 55,507 ops/sec [54,999..56,427] ~ overlap (-0.1%)
tag with 3 substitutions 19,224 ops/sec [18,796..19,418] → 19,044 ops/sec [18,887..19,660] ~ overlap (-0.9%) 31,514 ops/sec [30,977..32,526] → 30,241 ops/sec [29,680..30,630] 🔴 -4.0%
tag with 6 substitutions 11,300 ops/sec [11,217..11,338] → 11,317 ops/sec [11,127..11,680] ~ overlap (+0.2%) 18,409 ops/sec [18,295..18,749] → 17,725 ops/sec [17,658..18,046] 🔴 -3.7%
String.raw, no substitutions 238,226 ops/sec [233,157..239,892] → 237,323 ops/sec [231,656..240,747] ~ overlap (-0.4%) 277,207 ops/sec [269,405..278,904] → 257,923 ops/sec [256,128..263,062] 🔴 -7.0%
String.raw, 2 substitutions 171,518 ops/sec [170,238..176,297] → 174,855 ops/sec [173,235..175,418] ~ overlap (+1.9%) 201,449 ops/sec [198,243..205,569] → 194,722 ops/sec [193,650..195,854] 🔴 -3.3%
tag accessing .raw array 70,045 ops/sec [67,860..70,743] → 69,670 ops/sec [68,869..70,802] ~ overlap (-0.5%) 101,369 ops/sec [101,113..103,847] → 100,390 ops/sec [99,995..102,469] ~ overlap (-1.0%)
method as tag (this binding) 26,060 ops/sec [25,639..26,421] → 25,976 ops/sec [25,627..26,108] ~ overlap (-0.3%) 43,600 ops/sec [43,146..43,940] → 42,047 ops/sec [41,144..42,835] 🔴 -3.6%
tsv.js — Interp: 9 unch. · avg -0.1% · Bytecode: 🔴 1, 8 unch. · avg +0.3%
Benchmark Interpreted Δ Bytecode Δ
parse simple 3-column TSV 47,507 ops/sec [46,979..47,708] → 48,023 ops/sec [46,567..48,636] ~ overlap (+1.1%) 53,587 ops/sec [53,128..55,390] → 54,358 ops/sec [53,582..55,109] ~ overlap (+1.4%)
parse 10-row TSV 12,957 ops/sec [12,868..13,332] → 12,929 ops/sec [12,872..13,022] ~ overlap (-0.2%) 14,702 ops/sec [14,626..14,907] → 14,499 ops/sec [14,283..14,651] ~ overlap (-1.4%)
parse 100-row TSV 2,016 ops/sec [2,005..2,053] → 2,012 ops/sec [1,978..2,041] ~ overlap (-0.2%) 2,256 ops/sec [2,179..2,319] → 2,270 ops/sec [2,229..2,305] ~ overlap (+0.6%)
parse TSV with backslash-escaped fields 9,377 ops/sec [9,083..9,417] → 9,297 ops/sec [9,185..9,370] ~ overlap (-0.9%) 10,552 ops/sec [10,300..10,853] → 10,479 ops/sec [10,142..10,908] ~ overlap (-0.7%)
parse without headers (array of arrays) 5,574 ops/sec [5,549..5,643] → 5,582 ops/sec [5,465..5,724] ~ overlap (+0.1%) 6,259 ops/sec [6,212..6,358] → 6,418 ops/sec [6,320..6,478] ~ overlap (+2.5%)
stringify array of objects 39,794 ops/sec [39,554..39,909] → 40,187 ops/sec [39,461..40,746] ~ overlap (+1.0%) 46,311 ops/sec [45,737..48,250] → 46,948 ops/sec [46,844..47,702] ~ overlap (+1.4%)
stringify array of arrays 11,418 ops/sec [11,398..11,441] → 11,497 ops/sec [11,350..11,584] ~ overlap (+0.7%) 13,272 ops/sec [13,218..13,348] → 13,085 ops/sec [12,824..13,194] 🔴 -1.4%
stringify with values needing escaping 30,703 ops/sec [30,319..30,922] → 30,527 ops/sec [29,979..30,638] ~ overlap (-0.6%) 35,880 ops/sec [35,067..36,401] → 35,606 ops/sec [35,297..36,269] ~ overlap (-0.8%)
parse then stringify 7,229 ops/sec [7,173..7,269] → 7,092 ops/sec [6,967..7,249] ~ overlap (-1.9%) 8,109 ops/sec [7,936..8,369] → 8,156 ops/sec [8,108..8,433] ~ overlap (+0.6%)
typed-arrays.js — Interp: 🟢 10, 🔴 2, 10 unch. · avg +14.5% · Bytecode: 🟢 6, 🔴 6, 10 unch. · avg -1.9%
Benchmark Interpreted Δ Bytecode Δ
new Int32Array(0) 137,012 ops/sec [135,388..138,210] → 136,857 ops/sec [134,511..142,028] ~ overlap (-0.1%) 170,888 ops/sec [169,483..171,336] → 174,810 ops/sec [170,528..180,271] ~ overlap (+2.3%)
new Int32Array(100) 126,802 ops/sec [121,344..130,157] → 129,503 ops/sec [126,072..132,711] ~ overlap (+2.1%) 156,308 ops/sec [154,369..157,530] → 156,311 ops/sec [154,976..158,531] ~ overlap (+0.0%)
new Int32Array(1000) 91,834 ops/sec [90,262..94,189] → 93,394 ops/sec [92,553..94,340] ~ overlap (+1.7%) 102,983 ops/sec [101,454..104,110] → 106,655 ops/sec [104,536..107,830] 🟢 +3.6%
new Float64Array(100) 120,262 ops/sec [119,892..121,148] → 125,116 ops/sec [123,179..127,581] 🟢 +4.0% 144,540 ops/sec [143,332..145,967] → 154,644 ops/sec [152,567..158,723] 🟢 +7.0%
Int32Array.from([...]) 88,656 ops/sec [88,516..90,810] → 88,133 ops/sec [87,841..90,369] ~ overlap (-0.6%) 102,603 ops/sec [101,574..103,388] → 103,817 ops/sec [102,236..107,545] ~ overlap (+1.2%)
Int32Array.of(1, 2, 3, 4, 5) 132,212 ops/sec [129,818..134,078] → 133,058 ops/sec [130,959..136,589] ~ overlap (+0.6%) 166,236 ops/sec [164,388..167,881] → 167,225 ops/sec [165,577..171,850] ~ overlap (+0.6%)
sequential write 100 elements 1,545 ops/sec [1,528..1,555] → 1,591 ops/sec [1,555..1,635] ~ overlap (+3.0%) 6,173 ops/sec [5,986..6,399] → 6,022 ops/sec [5,977..6,075] ~ overlap (-2.5%)
sequential read 100 elements 1,564 ops/sec [1,540..1,589] → 2,655 ops/sec [1,614..2,672] 🟢 +69.8% 5,774 ops/sec [5,726..5,926] → 5,994 ops/sec [5,923..6,115] ~ overlap (+3.8%)
Float64Array write 100 elements 1,456 ops/sec [1,442..1,499] → 1,464 ops/sec [1,441..1,485] ~ overlap (+0.5%) 4,207 ops/sec [4,198..4,216] → 4,286 ops/sec [4,243..4,297] 🟢 +1.9%
fill(42) 27,157 ops/sec [26,973..27,190] → 25,555 ops/sec [25,316..25,860] 🔴 -5.9% 28,931 ops/sec [28,551..29,218] → 27,793 ops/sec [27,697..27,901] 🔴 -3.9%
slice() 115,822 ops/sec [114,755..116,391] → 107,451 ops/sec [106,732..108,208] 🔴 -7.2% 136,645 ops/sec [134,836..136,973] → 136,883 ops/sec [136,453..138,894] ~ overlap (+0.2%)
map(x => x * 2) 2,697 ops/sec [2,668..2,773] → 4,603 ops/sec [4,578..4,684] 🟢 +70.6% 4,606 ops/sec [4,564..4,663] → 4,501 ops/sec [4,461..4,514] 🔴 -2.3%
filter(x => x > 50) 2,958 ops/sec [2,888..2,969] → 3,001 ops/sec [2,958..4,999] ~ overlap (+1.5%) 5,078 ops/sec [5,036..5,153] → 5,093 ops/sec [5,035..5,274] ~ overlap (+0.3%)
reduce (sum) 2,717 ops/sec [2,666..2,856] → 4,703 ops/sec [4,666..4,720] 🟢 +73.1% 4,336 ops/sec [4,284..4,401] → 4,440 ops/sec [4,406..4,451] 🟢 +2.4%
sort() 105,867 ops/sec [105,609..107,006] → 144,041 ops/sec [142,637..144,824] 🟢 +36.1% 126,869 ops/sec [124,419..127,259] → 125,840 ops/sec [124,555..126,188] ~ overlap (-0.8%)
indexOf() 198,724 ops/sec [196,959..200,801] → 314,331 ops/sec [307,987..315,394] 🟢 +58.2% 270,852 ops/sec [268,232..272,044] → 275,105 ops/sec [272,649..277,959] 🟢 +1.6%
reverse() 253,043 ops/sec [250,570..256,866] → 253,488 ops/sec [252,218..253,945] ~ overlap (+0.2%) 311,932 ops/sec [310,568..312,990] → 217,790 ops/sec [214,833..218,607] 🔴 -30.2%
create view over existing buffer 251,463 ops/sec [247,439..253,061] → 256,142 ops/sec [253,610..257,383] 🟢 +1.9% 322,987 ops/sec [320,402..326,437] → 203,814 ops/sec [203,590..204,338] 🔴 -36.9%
subarray() 290,716 ops/sec [287,990..294,067] → 300,963 ops/sec [299,503..302,501] 🟢 +3.5% 409,851 ops/sec [406,339..414,129] → 263,655 ops/sec [261,740..265,568] 🔴 -35.7%
set() from array 366,922 ops/sec [364,826..368,550] → 366,427 ops/sec [365,322..368,231] ~ overlap (-0.1%) 310,335 ops/sec [308,844..312,403] → 303,141 ops/sec [301,045..307,767] 🔴 -2.3%
for-of loop 3,860 ops/sec [3,828..3,884] → 3,953 ops/sec [3,922..3,974] 🟢 +2.4% 9,678 ops/sec [9,339..14,181] → 13,763 ops/sec [13,573..14,024] ~ overlap (+42.2%)
spread into array 14,683 ops/sec [14,602..14,785] → 15,071 ops/sec [15,008..15,196] 🟢 +2.6% 58,163 ops/sec [57,161..59,214] → 61,008 ops/sec [60,896..61,075] 🟢 +4.9%
uint8array-encoding.js — Interp: 🟢 5, 🔴 2, 11 unch. · avg +20.7% · Bytecode: 🟢 7, 🔴 5, 6 unch. · avg +4.4%
Benchmark Interpreted Δ Bytecode Δ
short (5 bytes) 277,639 ops/sec [268,909..279,276] → 279,546 ops/sec [278,295..281,298] ~ overlap (+0.7%) 535,377 ops/sec [530,519..536,610] → 530,652 ops/sec [526,424..538,201] ~ overlap (-0.9%)
medium (450 bytes) 153,917 ops/sec [151,350..156,051] → 154,883 ops/sec [153,907..158,416] ~ overlap (+0.6%) 211,472 ops/sec [209,612..218,019] → 211,004 ops/sec [209,178..213,826] ~ overlap (-0.2%)
large (4096 bytes) 33,277 ops/sec [32,345..34,430] → 32,954 ops/sec [31,074..33,402] ~ overlap (-1.0%) 35,828 ops/sec [35,736..37,224] → 35,099 ops/sec [34,784..36,326] ~ overlap (-2.0%)
base64url alphabet 111,428 ops/sec [110,389..114,646] → 109,151 ops/sec [108,436..111,115] ~ overlap (-2.0%) 127,641 ops/sec [126,691..129,776] → 130,453 ops/sec [128,661..130,850] ~ overlap (+2.2%)
omitPadding 166,762 ops/sec [163,318..169,170] → 165,658 ops/sec [164,014..166,845] ~ overlap (-0.7%) 213,076 ops/sec [209,409..217,607] → 221,962 ops/sec [219,018..222,687] 🟢 +4.2%
short (8 chars) 148,777 ops/sec [144,134..150,251] → 149,744 ops/sec [148,761..150,646] ~ overlap (+0.7%) 177,697 ops/sec [175,480..179,544] → 183,559 ops/sec [182,321..186,019] 🟢 +3.3%
medium (600 chars) 72,124 ops/sec [71,491..75,082] → 70,422 ops/sec [69,621..70,608] 🔴 -2.4% 81,170 ops/sec [81,098..81,570] → 79,338 ops/sec [78,657..80,094] 🔴 -2.3%
large (5464 chars) 14,080 ops/sec [13,906..14,716] → 23,637 ops/sec [13,277..25,215] ~ overlap (+67.9%) 14,559 ops/sec [14,476..14,918] → 13,936 ops/sec [13,851..14,415] 🔴 -4.3%
short (5 bytes) 306,940 ops/sec [299,829..308,683] → 493,899 ops/sec [490,935..494,261] 🟢 +60.9% 558,695 ops/sec [556,100..560,808] → 571,897 ops/sec [568,441..580,665] 🟢 +2.4%
medium (450 bytes) 132,011 ops/sec [130,787..132,672] → 224,230 ops/sec [223,373..225,757] 🟢 +69.9% 166,091 ops/sec [164,909..166,264] → 177,097 ops/sec [175,367..177,380] 🟢 +6.6%
large (4096 bytes) 23,540 ops/sec [22,191..24,173] → 41,344 ops/sec [41,113..41,641] 🟢 +75.6% 25,213 ops/sec [24,961..25,479] → 26,849 ops/sec [26,684..27,419] 🟢 +6.5%
short (10 chars) 162,995 ops/sec [161,109..169,846] → 262,867 ops/sec [255,260..264,656] 🟢 +61.3% 198,913 ops/sec [198,453..199,661] → 207,420 ops/sec [206,653..208,176] 🟢 +4.3%
medium (900 chars) 108,692 ops/sec [106,627..111,032] → 181,205 ops/sec [102,674..181,934] ~ overlap (+66.7%) 194,324 ops/sec [122,116..197,976] → 118,659 ops/sec [117,652..120,738] 🔴 -38.9%
large (8192 chars) 27,573 ops/sec [26,625..28,995] → 25,391 ops/sec [24,270..27,040] ~ overlap (-7.9%) 28,933 ops/sec [28,038..29,681] → 27,424 ops/sec [26,936..27,837] 🔴 -5.2%
setFromBase64 (450 bytes) 71,963 ops/sec [71,314..78,577] → 117,090 ops/sec [116,099..119,463] 🟢 +62.7% 84,778 ops/sec [84,406..86,013] → 83,622 ops/sec [83,372..83,710] 🔴 -1.4%
setFromHex (450 bytes) 168,736 ops/sec [167,502..169,122] → 166,307 ops/sec [165,881..167,630] ~ overlap (-1.4%) 126,743 ops/sec [123,282..128,149] → 124,308 ops/sec [121,274..125,423] ~ overlap (-1.9%)
toBase64 → fromBase64 (450 bytes) 88,008 ops/sec [87,058..89,142] → 54,032 ops/sec [53,173..87,502] ~ overlap (-38.6%) 62,449 ops/sec [62,235..62,520] → 94,570 ops/sec [92,200..95,145] 🟢 +51.4%
toHex → fromHex (450 bytes) 112,458 ops/sec [111,656..112,965] → 67,300 ops/sec [65,414..68,166] 🔴 -40.2% 75,664 ops/sec [74,070..118,847] → 117,714 ops/sec [115,494..118,494] ~ overlap (+55.6%)
weak-collections.js — Interp: 🟢 2, 🔴 8, 5 unch. · avg -8.9% · Bytecode: 🟢 7, 🔴 1, 7 unch. · avg +28.0%
Benchmark Interpreted Δ Bytecode Δ
constructor from 50 entries 12,456 ops/sec [12,064..12,699] → 12,829 ops/sec [12,624..13,211] ~ overlap (+3.0%) 13,930 ops/sec [13,670..14,132] → 13,627 ops/sec [13,296..14,380] ~ overlap (-2.2%)
set 50 object keys 4,592 ops/sec [4,544..4,626] → 4,636 ops/sec [4,447..4,682] ~ overlap (+1.0%) 6,843 ops/sec [6,701..6,975] → 7,039 ops/sec [6,995..7,404] 🟢 +2.9%
get lookups (50 entries) 59,743 ops/sec [58,510..59,942] → 58,064 ops/sec [57,383..58,447] 🔴 -2.8% 109,109 ops/sec [104,522..111,681] → 105,771 ops/sec [104,287..108,273] ~ overlap (-3.1%)
has checks (50 entries) 78,212 ops/sec [77,715..79,312] → 75,607 ops/sec [75,101..77,593] 🔴 -3.3% 135,837 ops/sec [134,265..137,200] → 135,751 ops/sec [134,738..138,375] ~ overlap (-0.1%)
delete entries 7,008 ops/sec [6,714..7,034] → 4,274 ops/sec [4,110..4,446] 🔴 -39.0% 6,623 ops/sec [6,608..6,641] → 6,555 ops/sec [6,505..6,639] ~ overlap (-1.0%)
non-registered symbol keys 16,941 ops/sec [16,832..16,971] → 10,392 ops/sec [10,325..10,749] 🔴 -38.7% 15,722 ops/sec [15,622..15,754] → 23,644 ops/sec [15,709..26,315] ~ overlap (+50.4%)
getOrInsert 6,785 ops/sec [6,747..6,851] → 4,185 ops/sec [4,157..4,217] 🔴 -38.3% 6,337 ops/sec [6,234..6,383] → 10,877 ops/sec [10,753..11,004] 🟢 +71.6%
getOrInsertComputed 3,366 ops/sec [3,326..3,386] → 2,165 ops/sec [2,112..2,179] 🔴 -35.7% 3,020 ops/sec [2,951..3,083] → 4,976 ops/sec [4,923..5,048] 🟢 +64.8%
forced gc live-key retention 7,103 ops/sec [7,062..7,118] → 4,448 ops/sec [4,379..4,494] 🔴 -37.4% 5,929 ops/sec [5,816..5,973] → 9,343 ops/sec [9,214..9,455] 🟢 +57.6%
constructor from 50 values 26,691 ops/sec [25,843..27,314] → 16,766 ops/sec [16,564..16,847] 🔴 -37.2% 19,150 ops/sec [18,949..20,178] → 29,563 ops/sec [29,270..29,693] 🟢 +54.4%
add 50 object values 7,974 ops/sec [7,938..8,024] → 6,166 ops/sec [4,931..8,074] ~ overlap (-22.7%) 7,669 ops/sec [7,588..7,748] → 12,491 ops/sec [12,439..12,629] 🟢 +62.9%
has checks (50 values) 127,398 ops/sec [126,005..127,546] → 126,846 ops/sec [126,704..127,259] ~ overlap (-0.4%) 135,445 ops/sec [133,095..137,347] → 226,204 ops/sec [224,354..227,309] 🟢 +67.0%
delete values 12,985 ops/sec [12,640..13,065] → 21,092 ops/sec [20,891..21,256] 🟢 +62.4% 26,439 ops/sec [24,439..26,677] → 26,127 ops/sec [25,999..26,183] ~ overlap (-1.2%)
non-registered symbol values 11,174 ops/sec [11,076..11,199] → 17,592 ops/sec [17,408..17,911] 🟢 +57.4% 28,136 ops/sec [27,605..28,158] → 27,928 ops/sec [27,821..28,204] ~ overlap (-0.7%)
forced gc pruning smoke 8,690 ops/sec [8,613..8,814] → 8,584 ops/sec [8,504..8,634] ~ overlap (-1.2%) 12,112 ops/sec [11,873..12,198] → 11,670 ops/sec [11,343..11,747] 🔴 -3.6%

Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 8269 8269
Tests Passed 8228 ✅ 8269 ✅
Tests Skipped 41 0
Tests Workers 4 4
Tests Test Duration 1.91s 2.00s
Tests Lex (cumulative) 204.5ms 144.4ms
Tests Parse (cumulative) 318.1ms 340.0ms
Tests Compile (cumulative) 213.2ms
Tests Execute (cumulative) 1.78s 1.60s
Tests Engine Total (cumulative) 2.30s 2.29s
Tests Lex (avg/worker) 51.1ms 36.1ms
Tests Parse (avg/worker) 79.5ms 85.0ms
Tests Compile (avg/worker) 53.3ms
Tests Execute (avg/worker) 444.0ms 399.2ms
Tests Engine Total (avg/worker) 574.6ms 573.6ms
Benchmarks Total 407 407
Benchmarks Workers 4 4
Benchmarks Duration 2.49min 2.36min

Measured on ubuntu-latest x64.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
website/src/lib/goccia-api.ts (1)

18-22: ⚠️ Potential issue | 🟠 Major

Widen the pre-parse body cap.

MAX_BODY_BYTES = MAX_CODE_BYTES + 1_024 is too tight now that the code limit is only 8 KiB: valid snippets can still serialize to more than 9 KiB of JSON when they contain lots of escapes or newlines, so the request gets rejected before the later byte check runs. Please make this envelope cap much more generous or move the enforcement to a post-parse check.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/lib/goccia-api.ts` around lines 18 - 22, The pre-parse envelope
cap MAX_BODY_BYTES is too small (MAX_CODE_BYTES + 1_024) and rejects valid JSON
that expands with escapes/newlines; increase the allowance or defer enforcement
until after JSON.parse. Update the MAX_BODY_BYTES definition in
website/src/lib/goccia-api.ts (the MAX_BODY_BYTES and MAX_CODE_BYTES symbols) to
a much more generous value (e.g. add ~8 KiB–64 KiB headroom or use
MAX_CODE_BYTES * 2) or remove the strict pre-parse cap and perform the size
check after parsing the body so the existing per-field byte validation still
runs.
🧹 Nitpick comments (1)
website/src/components/webmcp-tools.tsx (1)

113-127: Avoid unhandled promise rejections in context registration calls.

Lines 114 and 127 intentionally discard promises. If either async API rejects, it can surface as unhandled rejection noise in production.

Suggested fix
+const swallow = <T,>(p: Promise<T>) => p.catch(() => undefined);
+
 export function WebMcpTools() {
   useEffect(() => {
@@
     const tools = buildTools();
     if (modelContext.provideContext) {
-      void modelContext.provideContext({ tools });
+      void swallow(Promise.resolve(modelContext.provideContext({ tools })));
       return () => {
         if (modelContext.clearContext) {
-          void modelContext.clearContext();
+          void swallow(Promise.resolve(modelContext.clearContext()));
         } else {
-          void modelContext.provideContext?.({ tools: [] });
+          void swallow(Promise.resolve(modelContext.provideContext?.({ tools: [] })));
         }
       };
     }
@@
     const controller = new AbortController();
     for (const tool of tools) {
-      void modelContext.registerTool(tool, { signal: controller.signal });
+      void swallow(
+        Promise.resolve(modelContext.registerTool(tool, { signal: controller.signal })),
+      );
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/components/webmcp-tools.tsx` around lines 113 - 127, The code
currently discards promises from modelContext.provideContext,
modelContext.clearContext and modelContext.registerTool which can lead to
unhandled promise rejections; update the logic to handle rejections by awaiting
these calls or attaching .catch handlers (e.g., await or void
promise.catch(...)) and ensure registerTool loop respects the AbortController
signal and handles per-tool rejections so failures are logged/ignored instead of
bubbling as unhandled rejections; specifically update usages of
modelContext.provideContext, modelContext.clearContext and
modelContext.registerTool (and the AbortController usage) to consistently handle
async errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@website/src/app/.well-known/mcp/server-card.json/route.ts`:
- Around line 27-30: The GET handler currently calls fetchLatestRelease without
handling failures, so wrap the call in a try/catch (or check its result) and
ensure you pass a fallback tag value of "nightly" into
buildMcpServerCardResponse when fetchLatestRelease throws or returns undefined;
update the GET function to catch errors from fetchLatestRelease and set const
tag = release?.tagName ?? "nightly" (or assign "nightly" in the catch) before
calling buildMcpServerCardResponse so the well-known endpoint always returns
discovery metadata.

In `@website/src/components/webmcp-tools.tsx`:
- Around line 61-67: The current code calls fetch(endpoint, ...) and awaits
response, but if fetch rejects (network/CORS/offline) the async call will throw
and `execute` will propagate an exception instead of returning the consistent
tool result object; update the call site in the function (e.g., the execute
handler that builds `endpoint`/`payload` and currently assigns
`response`/`body`) to wrap the fetch + response.json() in a try/catch and on any
transport or parse error return a normalized tool response object (use the same
schema other branches return — e.g., an object with an error/status field and
the original endpoint/payload context) rather than letting the exception escape;
ensure you still attempt response.json() only when response is available and
include any available status/code in the normalized response.

In `@website/src/lib/agent-discovery.ts`:
- Around line 85-86: The discovery metadata currently advertises OAuth/OIDC
features that aren't implemented: remove the unsupported fields
(id_token_signing_alg_values_supported, jwks_uri, token_endpoint and any
id_token-related entries in claims_supported) from the discovery object so the
advertised capabilities match the running server; alternatively, if you prefer
to support OIDC, implement the missing pieces instead: add route handlers for
/oauth/token and /oauth/authorize, serve a valid JWKS at the declared jwks_uri,
integrate a JWT library to sign id_tokens with RS256 and expose the public key
in the JWKS, and ensure claims_supported only lists claims you actually emit.

In `@website/src/lib/goccia-tool-schema.ts`:
- Around line 1-12: The JSON schema in gocciaRunInputSchema uses maxLength
(character count) but MAX_GOCCIA_CODE_BYTES is a byte limit, so either enforce
byte-length at schema-validation time or document the mismatch: implement a
byte-aware check by adding a custom schema keyword/format (e.g., "maxBytes":
MAX_GOCCIA_CODE_BYTES) and register a validator that calls
Buffer.byteLength(value, "utf8") <= MAX_GOCCIA_CODE_BYTES (tie this into the
same validator used for gocciaRunInputSchema), or alternatively update the code
property's description to explicitly state maxLength is character-based and that
the server-side function (the runtime check in goccia-api.ts that uses
Buffer.byteLength) is the authoritative byte limit; pick one approach and apply
consistently so MAX_GOCCIA_CODE_BYTES and gocciaRunInputSchema remain correct
and unambiguous.

---

Outside diff comments:
In `@website/src/lib/goccia-api.ts`:
- Around line 18-22: The pre-parse envelope cap MAX_BODY_BYTES is too small
(MAX_CODE_BYTES + 1_024) and rejects valid JSON that expands with
escapes/newlines; increase the allowance or defer enforcement until after
JSON.parse. Update the MAX_BODY_BYTES definition in
website/src/lib/goccia-api.ts (the MAX_BODY_BYTES and MAX_CODE_BYTES symbols) to
a much more generous value (e.g. add ~8 KiB–64 KiB headroom or use
MAX_CODE_BYTES * 2) or remove the strict pre-parse cap and perform the size
check after parsing the body so the existing per-field byte validation still
runs.

---

Nitpick comments:
In `@website/src/components/webmcp-tools.tsx`:
- Around line 113-127: The code currently discards promises from
modelContext.provideContext, modelContext.clearContext and
modelContext.registerTool which can lead to unhandled promise rejections; update
the logic to handle rejections by awaiting these calls or attaching .catch
handlers (e.g., await or void promise.catch(...)) and ensure registerTool loop
respects the AbortController signal and handles per-tool rejections so failures
are logged/ignored instead of bubbling as unhandled rejections; specifically
update usages of modelContext.provideContext, modelContext.clearContext and
modelContext.registerTool (and the AbortController usage) to consistently handle
async errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b1257f32-67e8-451a-a3a6-44ee28d2c060

📥 Commits

Reviewing files that changed from the base of the PR and between ba88a51 and 9ebf514.

📒 Files selected for processing (13)
  • website/src/__tests__/agent-discovery.test.ts
  • website/src/app/.well-known/agent-skills/gocciascript-api/SKILL.md/route.ts
  • website/src/app/.well-known/agent-skills/index.json/route.ts
  • website/src/app/.well-known/jwks.json/route.ts
  • website/src/app/.well-known/mcp/server-card.json/route.ts
  • website/src/app/.well-known/oauth-authorization-server/route.ts
  • website/src/app/.well-known/oauth-protected-resource/route.ts
  • website/src/app/.well-known/openid-configuration/route.ts
  • website/src/app/layout.tsx
  • website/src/components/webmcp-tools.tsx
  • website/src/lib/agent-discovery.ts
  • website/src/lib/goccia-api.ts
  • website/src/lib/goccia-tool-schema.ts

Comment thread website/src/app/.well-known/mcp/server-card.json/route.ts Outdated
Comment thread website/src/components/webmcp-tools.tsx Outdated
Comment thread website/src/lib/agent-discovery.ts Outdated
Comment thread website/src/lib/goccia-tool-schema.ts
@frostney frostney marked this pull request as draft April 29, 2026 13:29
@frostney frostney marked this pull request as ready for review April 29, 2026 15:07
@coderabbitai coderabbitai Bot added the internal Refactoring, CI, tooling, cleanup label Apr 29, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
website/src/lib/agent-discovery.ts (1)

68-80: ⚠️ Potential issue | 🟠 Major

/.well-known/openid-configuration is still not valid OIDC metadata.

buildOpenIdConfiguration() just mirrors the OAuth AS fields, but OpenID Discovery requires the openid scope and required OP metadata such as subject_types_supported and id_token_signing_alg_values_supported. RFC 8414 also says zero-element claims must be omitted, so response_types_supported: [] / grant_types_supported: [] are not valid authorization-server metadata either. Either remove the OpenID document until the site is a real OP, or publish a fully conforming provider document. (openid.net)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/lib/agent-discovery.ts` around lines 68 - 80, The OpenID document
generated by buildOpenIdConfiguration() is invalid: update
buildOAuthAuthorizationServerMetadata(origin) and/or
buildOpenIdConfiguration(origin) so they omit empty-array claims (do not return
response_types_supported: [] or grant_types_supported: []), ensure
scopes_supported includes "openid" (API_SCOPES must contain "openid" for OIDC),
and when exposing OpenID configuration include required OP metadata such as
subject_types_supported and id_token_signing_alg_values_supported (and any other
mandatory OpenID Connect Discovery fields). Alternatively, if you do not intend
to act as an OpenID Provider, remove buildOpenIdConfiguration() / the
/.well-known/openid-configuration endpoint so you do not publish a
non-conformant document.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@website/src/lib/goccia-tool-schema.ts`:
- Around line 86-121: The exported JSON Schema from gocciaRunInputSchema
currently marks "code" as required but omits the non-empty constraint, allowing
clients to send an empty string that the runtime rejects; update the "code"
property in gocciaRunInputSchema to include minLength: 1 so the schema enforces
non-empty source code (keep existing description, maxBytes and required array
unchanged).
- Around line 64-84: validateGocciaToolInput currently maps missing/invalid
"code" to INVALID_INPUT because it only checks for "exceeds" in the message;
update the errorCode logic in validateGocciaToolInput (which uses
gocciaToolInputZodSchema.safeParse and returns GocciaToolValidationResult) to
return "MISSING_CODE" when the first Zod issue targets the "code" field and
indicates a missing/required value (e.g., issue.path[0] === "code" and either
issue.code corresponds to a missing/required error or issue.message includes
"Required" or similar), keep the existing "CODE_TOO_LARGE" branch for the
message.includes("exceeds") case, and fall back to "INVALID_INPUT" otherwise so
downstream code no longer needs to string-match for "code is required".

---

Duplicate comments:
In `@website/src/lib/agent-discovery.ts`:
- Around line 68-80: The OpenID document generated by buildOpenIdConfiguration()
is invalid: update buildOAuthAuthorizationServerMetadata(origin) and/or
buildOpenIdConfiguration(origin) so they omit empty-array claims (do not return
response_types_supported: [] or grant_types_supported: []), ensure
scopes_supported includes "openid" (API_SCOPES must contain "openid" for OIDC),
and when exposing OpenID configuration include required OP metadata such as
subject_types_supported and id_token_signing_alg_values_supported (and any other
mandatory OpenID Connect Discovery fields). Alternatively, if you do not intend
to act as an OpenID Provider, remove buildOpenIdConfiguration() / the
/.well-known/openid-configuration endpoint so you do not publish a
non-conformant document.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f755f6e1-6f7c-48db-9cd2-e63269ed9e6d

📥 Commits

Reviewing files that changed from the base of the PR and between 9ebf514 and 1c94f14.

⛔ Files ignored due to path filters (1)
  • website/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • website/package.json
  • website/src/__tests__/agent-discovery.test.ts
  • website/src/__tests__/goccia-tool-schema.test.ts
  • website/src/app/.well-known/mcp/server-card.json/route.ts
  • website/src/components/playground.tsx
  • website/src/components/webmcp-tools.tsx
  • website/src/lib/agent-discovery.ts
  • website/src/lib/goccia-api.ts
  • website/src/lib/goccia-tool-schema.ts
✅ Files skipped from review due to trivial changes (1)
  • website/package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • website/src/app/.well-known/mcp/server-card.json/route.ts
  • website/src/tests/agent-discovery.test.ts
  • website/src/components/webmcp-tools.tsx

Comment thread website/src/lib/goccia-tool-schema.ts
Comment thread website/src/lib/goccia-tool-schema.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
website/src/lib/goccia-tool-schema.ts (1)

64-66: Accept unknown in validateGocciaToolInput to remove caller casts.

Typing input as GocciaToolInput forces upstream as casts on untrusted JSON. Accepting unknown keeps type-safety at the boundary and improves ergonomics.

♻️ Proposed refactor
-export function validateGocciaToolInput(
-  input: GocciaToolInput,
-): GocciaToolValidationResult {
+export function validateGocciaToolInput(
+  input: unknown,
+): GocciaToolValidationResult {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/lib/goccia-tool-schema.ts` around lines 64 - 66, Change
validateGocciaToolInput signature to accept input: unknown instead of
GocciaToolInput and perform the necessary runtime narrowing/validation inside
the function so callers don’t need to cast untrusted JSON; update the
implementation in validateGocciaToolInput (and any helper functions it calls) to
validate fields and return a GocciaToolValidationResult (errors or parsed value)
based on those runtime checks, and then remove upstream `as` casts at call sites
that previously forced GocciaToolInput.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@website/src/lib/goccia-tool-schema.ts`:
- Around line 64-66: Change validateGocciaToolInput signature to accept input:
unknown instead of GocciaToolInput and perform the necessary runtime
narrowing/validation inside the function so callers don’t need to cast untrusted
JSON; update the implementation in validateGocciaToolInput (and any helper
functions it calls) to validate fields and return a GocciaToolValidationResult
(errors or parsed value) based on those runtime checks, and then remove upstream
`as` casts at call sites that previously forced GocciaToolInput.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9f2f3f28-bd92-48c0-b06a-af870b804b6b

📥 Commits

Reviewing files that changed from the base of the PR and between 1c94f14 and a0b759f.

📒 Files selected for processing (5)
  • website/src/__tests__/agent-discovery.test.ts
  • website/src/__tests__/goccia-tool-schema.test.ts
  • website/src/lib/agent-discovery.ts
  • website/src/lib/goccia-api.ts
  • website/src/lib/goccia-tool-schema.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/src/tests/goccia-tool-schema.test.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
website/src/lib/goccia-api.ts (1)

594-602: Remove redundant validator error-code remapping.

payload.error.code is already narrowed to "INVALID_INPUT" | "MISSING_CODE" | "CODE_TOO_LARGE", so the ternary adds maintenance overhead without changing behavior.

♻️ Proposed simplification
     return transportError(
       {
         message: payload.error.message,
-        code:
-          payload.error.code === "CODE_TOO_LARGE"
-            ? "CODE_TOO_LARGE"
-            : payload.error.code === "MISSING_CODE"
-              ? "MISSING_CODE"
-              : "INVALID_INPUT",
+        code: payload.error.code,
       },
       { status },
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/lib/goccia-api.ts` around lines 594 - 602, The ternary remapping
around payload.error.code in the error object is redundant; locate the object
construction that sets message: payload.error.message and code: (the ternary
chain comparing payload.error.code to "CODE_TOO_LARGE" and "MISSING_CODE") and
replace the conditional mapping with a direct assignment of payload.error.code
(i.e., set code to payload.error.code) so the function using payload.error.code
(and any types like the narrowed union) is used directly without extra
branching.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@website/src/lib/goccia-api.ts`:
- Around line 594-602: The ternary remapping around payload.error.code in the
error object is redundant; locate the object construction that sets message:
payload.error.message and code: (the ternary chain comparing payload.error.code
to "CODE_TOO_LARGE" and "MISSING_CODE") and replace the conditional mapping with
a direct assignment of payload.error.code (i.e., set code to payload.error.code)
so the function using payload.error.code (and any types like the narrowed union)
is used directly without extra branching.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: affe69a5-0f74-4568-a12b-9a75f32534d0

📥 Commits

Reviewing files that changed from the base of the PR and between a0b759f and 16381b7.

📒 Files selected for processing (4)
  • website/src/__tests__/goccia-tool-schema.test.ts
  • website/src/components/webmcp-tools.tsx
  • website/src/lib/goccia-api.ts
  • website/src/lib/goccia-tool-schema.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/src/tests/goccia-tool-schema.test.ts
  • website/src/components/webmcp-tools.tsx

@frostney frostney merged commit 00cf386 into main Apr 29, 2026
12 checks passed
@frostney frostney deleted the t3code/agent-discovery-metadata-1 branch April 29, 2026 16:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation internal Refactoring, CI, tooling, cleanup new feature New feature or request spec compliance Mismatch against official JavaScript/TypeScript specification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant