FAIL2.8
Loading cell…
Loading cell…
Write a TypeScript function named createIdempotencyGuard.
Requirements:
key, ttlMs, and an async handler function.Output format: { "code": "...", "explanation": "...", "complexity": { "time": "...", "space": "..." }, "tests": ["...", "...", "...", "...", "..."] }
{
"code": "type GuardStatus = 'pending' | 'resolved';\n\ninterface GuardEntry<T> {\n status: GuardStatus;\n promise: Promise<T>;\n value?: T;\n expiresAt?: number;\n timer?: ReturnType<typeof setTimeout>;\n}\n\n// Module-level store shared across all calls to createIdempotencyGuard.\n// Keyed by the caller-supplied idempotency key.\nconst store = new Map<string, GuardEntry<any>>();\n\ninterface IdempotencyGuardOptions<T> {\n key: string;\n ttlMs: number;\n handler: () => Promise<T>;\n}\n\n/**\n * Ensures that concurrent or repeated calls sharing the same `key`\n * are deduplicated:\n * - While a call for `key` is in flight, subsequent calls receive\n * the SAME Promise (no duplicate handler execution).\n * - After a successful resolution, the result is cached and returned\n * for `ttlMs` milliseconds without re-invoking the handler.\n * - If the handler rejects, nothing is cached; the next call for the\n * same key will re-run the handler from scratch.\n */\nexport function createIdempotencyGuard<T>(\n options: IdempotencyGuardOptions<T>\n): Promise<T> {\n const { key, ttlMs, handler } = options;\n const now = Date.now();\n\n const existing = store.get(key);\n\n if (existing) {\n if (existing.status === 'pending') {\n // A call for this key is already running; piggyback on it.\n return existing.promise;\n }\n\n if (\n existing.status === 'resolved' &&\n existing.expiresAt !== undefined &&\n existing.expiresAt > now\n ) {\n // Cached and still fresh.\n return Promise.resolve(existing.value as T);\n }\n\n // Entry exists but is stale (expired) or otherwise invalid; drop it\n // and fall through to re-run the handler.\n if (existing.timer) clearTimeout(existing.timer);\n store.delete(key);\n }\n\n const promise: Promise<T> = handler()\n .then((result) => {\n const expiresAt = Date.now() + ttlMs;\n const timer = setTimeout(() => {\n const current = store.get(key);\n // Only delete if it's still the same resolved entry (not replaced).\n if (current && current.status === 'resolved' && current.expiresAt === expiresAt)
0/2 checks passed