examples/MCP-tools Public
// Small stand-ins for the Workers runtime, enough for the code under test.import { take, type Bucket } from "../src/rate-limiter/bucket.ts";import type { RateLimiter } from "../src/rate-limiter/index.ts";type Entry = { value: string; metadata: unknown };// The parts of KVNamespace that src/usage.ts uses, over a Map. list() pages by `limit` so the// cursor loop gets exercised.export function fakeKv(limit = 1000): KVNamespace & { entries: Map<string, Entry> } { const entries = new Map<string, Entry>(); const kv = { entries, async get(key: string, type?: string) { const e = entries.get(key); if (!e) return null; return type === "json" ? JSON.parse(e.value) : e.value; }, async put(key: string, value: string, options?: { metadata?: unknown }) { entries.set(key, { value, metadata: options?.metadata ?? null }); }, async list(options: { prefix?: string; cursor?: string } = {}) { const names = [...entries.keys()].filter((k) => k.startsWith(options.prefix ?? "")).sort(); const start = Number(options.cursor ?? 0); const page = names.slice(start, start + limit); const done = start + limit >= names.length; return { keys: page.map((name) => ({ name, metadata: entries.get(name)!.metadata })), list_complete: done, ...(done ? {} : { cursor: String(start + limit) }), }; }, }; return kv as unknown as KVNamespace & { entries: Map<string, Entry> };}// An ExecutionContext that keeps what was handed to waitUntil, so a test can await it.export function fakeCtx(): ExecutionContext & { settle: () => Promise<void> } { const pending: Promise<unknown>[] = []; const ctx = { waitUntil: (p: Promise<unknown>) => void pending.push(p), passThroughOnException() {}, props: {}, settle: async () => void (await Promise.all(pending.splice(0))), }; return ctx as unknown as ExecutionContext & { settle: () => Promise<void> };}// A RATE_LIMITER namespace with one in-memory bucket per name, running the real bucket logic// against a clock the test controls.export function fakeLimiter(clock = { now: 0 }): DurableObjectNamespace<RateLimiter> & { clock: { now: number } } { const buckets = new Map<string, Bucket>(); const ns = { clock, getByName(name: string) { return { async take() { const { bucket, decision } = take(buckets.get(name), clock.now); buckets.set(name, bucket); return decision; }, }; }, }; return ns as unknown as DurableObjectNamespace<RateLimiter> & { clock: { now: number } };}