bun-runtime-expert — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited bun-runtime-expert (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Fast, all-in-one JavaScript/TypeScript runtime — server, bundler, package manager, test runner.
| Feature | Bun | Node.js |
|---|---|---|
| Startup time | ~5ms | ~50ms |
bun install | ~100ms | npm: ~3s |
| Built-in SQLite | ✅ | ❌ |
| Built-in test runner | ✅ | ❌ (need Jest) |
| Built-in bundler | ✅ | ❌ (need webpack) |
| TypeScript natively | ✅ | ❌ (need ts-node) |
| Web APIs (fetch, Request) | ✅ native | Partial |
Bun.serveconst server = Bun.serve({
port: 3000,
hostname: "0.0.0.0",
async fetch(req: Request): Promise<Response> {
const url = new URL(req.url)
if (url.pathname === "/health") {
return Response.json({ status: "ok" })
}
if (url.pathname === "/api/users" && req.method === "GET") {
const users = await getUsers()
return Response.json(users)
}
if (url.pathname === "/api/users" && req.method === "POST") {
const body = await req.json()
const user = await createUser(body)
return Response.json(user, { status: 201 })
}
return new Response("Not Found", { status: 404 })
},
error(err: Error): Response {
console.error(err)
return Response.json({ error: "Internal Server Error" }, { status: 500 })
},
})
console.log(`Server running at http://localhost:${server.port}`)type Handler = (req: Request, params: Record<string, string>) => Promise<Response>
class Router {
private routes = new Map<string, Handler>()
add(method: string, path: string, handler: Handler) {
this.routes.set(`${method}:${path}`, handler)
return this
}
get(path: string, handler: Handler) { return this.add("GET", path, handler) }
post(path: string, handler: Handler) { return this.add("POST", path, handler) }
put(path: string, handler: Handler) { return this.add("PUT", path, handler) }
delete(path: string, handler: Handler) { return this.add("DELETE", path, handler) }
async handle(req: Request): Promise<Response> {
const url = new URL(req.url)
const key = `${req.method}:${url.pathname}`
const handler = this.routes.get(key)
if (!handler) return new Response("Not Found", { status: 404 })
return handler(req, {})
}
}
const router = new Router()
.get("/api/posts", listPosts)
.post("/api/posts", createPost)
.get("/api/posts/:id", getPost)
Bun.serve({ fetch: req => router.handle(req) })Bun.serve({
fetch(req, server) {
if (server.upgrade(req)) return // Upgraded to WS
return new Response("HTTP response")
},
websocket: {
open(ws) {
ws.subscribe("chat")
ws.send(JSON.stringify({ type: "connected" }))
},
message(ws, message) {
// Broadcast to all subscribers
ws.publish("chat", message)
},
close(ws) {
ws.unsubscribe("chat")
},
},
})Bun.sqlimport { sql } from "bun"
// Bun.sql uses tagged template literals — SQL injection safe
const users = await sql`SELECT * FROM users WHERE active = ${true}`
// With types
type User = { id: string; email: string; name: string }
const user = await sql<User[]>`
SELECT id, email, name
FROM users
WHERE email = ${email}
LIMIT 1
`
// Transactions
await sql.begin(async (tx) => {
const [newUser] = await tx<User[]>`
INSERT INTO users (email, name) VALUES (${email}, ${name})
RETURNING *
`
await tx`
INSERT INTO audit_log (user_id, action) VALUES (${newUser.id}, 'signup')
`
return newUser
})
// Configure connection
const db = new Bun.SQL({
url: process.env.DATABASE_URL,
max: 20, // pool size
idleTimeout: 30, // seconds
})import { Database } from "bun:sqlite"
const db = new Database("mydb.sqlite")
// Prepare statements (reuse for performance)
const getUser = db.prepare<{ id: number; name: string }, [string]>(
"SELECT id, name FROM users WHERE email = ?"
)
const user = getUser.get("[email protected]")
// Transactions
const insertUser = db.prepare("INSERT INTO users (email, name) VALUES (?, ?)")
const insertLog = db.prepare("INSERT INTO logs (user_id) VALUES (?)")
const signup = db.transaction((email: string, name: string) => {
const info = insertUser.run(email, name)
insertLog.run(info.lastInsertRowid)
return info.lastInsertRowid
})
const id = signup("[email protected]", "Bob")Bun.s3// Configure (auto-reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
const s3 = new Bun.S3Client({
bucket: "my-bucket",
region: "us-east-1",
// Or use custom endpoint for R2/MinIO:
endpoint: "https://xxx.r2.cloudflarestorage.com",
})
// Upload
await s3.write("uploads/avatar.png", imageBuffer, {
type: "image/png",
acl: "public-read",
})
// Download
const file = s3.file("uploads/avatar.png")
const buffer = await file.arrayBuffer()
// Presigned URL
const url = await s3.presign("uploads/avatar.png", {
expiresIn: 3600, // 1 hour
method: "GET",
})
// Delete
await s3.delete("uploads/old-avatar.png")
// List
const objects = await s3.list({ prefix: "uploads/" })bun:test// math.test.ts
import { describe, it, expect, beforeEach, afterEach, mock, spyOn } from "bun:test"
describe("Calculator", () => {
it("adds two numbers", () => {
expect(1 + 2).toBe(3)
})
it("handles async operations", async () => {
const result = await fetchData("https://api.example.com")
expect(result).toMatchObject({ status: "ok" })
})
it("mocks functions", () => {
const mockFetch = mock(() => Promise.resolve({ ok: true }))
globalThis.fetch = mockFetch as any
// test code that calls fetch...
expect(mockFetch).toHaveBeenCalledTimes(1)
})
})
// Snapshot testing
it("renders correctly", () => {
const output = renderComponent()
expect(output).toMatchSnapshot()
})# Run tests
bun test
# Watch mode
bun test --watch
# Coverage
bun test --coverage
# Filter by name
bun test --test-name-pattern "Calculator"
# Specific file
bun test math.test.ts// build.ts
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
target: "browser", // or "node" or "bun"
format: "esm", // or "cjs" or "iife"
splitting: true, // code splitting
minify: true,
sourcemap: "external",
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
},
plugins: [
// Custom plugins (compatible with esbuild API)
],
})# Build from CLI
bun build ./src/index.ts --outdir ./dist --minify
# Bundle to single file
bun build ./src/index.ts --outfile ./dist/bundle.js# Install (fastest package manager)
bun install # install from package.json
bun add express # add dependency
bun add -d @types/bun # add devDependency
bun remove express # remove
bun update # update all
# Run scripts
bun run dev
bun run build
# Execute files
bun index.ts # run TypeScript directly
bun --watch index.ts # hot reload
# Workspaces
bun install # installs all workspace packagesbunfig.toml Configuration[install]
registry = "https://registry.npmjs.org"
frozen = true # like --frozen-lockfile
[run]
bun = true # prefer bun over node for scripts$)import { $ } from "bun"
// Run shell commands
const result = await $`ls -la`.text()
// Pipe
const count = await $`cat package.json | grep name`.text()
// Template with variables (auto-escaped)
const filename = "my file.txt"
await $`rm ${filename}` // safe: rm "my file.txt"
// Capture output
const { stdout, stderr, exitCode } = await $`git status`.quiet()
// Write file
await $`echo "hello" > output.txt`
// Script mode
await $`
mkdir -p dist
bun build ./src/index.ts --outdir dist
echo "Build complete"
`fs.readFileerror() for uncaught handler errorsmax on Bun.SQL for production~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.