fix(realtime-token): spend the session quota only after a token is minted and stop leaking provider errors

This commit is contained in:
Yun Chan 2026-09-28 00:54:00 +09:00
parent 83c2deb561
commit 2251fe2da1
7 changed files with 673 additions and 155 deletions

View file

@ -0,0 +1,32 @@
// Source-order contract for realtime-token: provider availability and minting
// must precede the quota spend, and raw errors must never reach the response.
const index = await Deno.readTextFile(new URL('./index.ts', import.meta.url))
const handler = await Deno.readTextFile(new URL('./handler.ts', import.meta.url))
const provider = await Deno.readTextFile(new URL('./openai-provider.ts', import.meta.url))
function assert(condition: boolean, message: string): asserts condition {
if (!condition) throw new Error(message)
}
Deno.test('index is only a composition root over the tested handler', () => {
assert(index.includes('createRealtimeTokenHandler('), 'index must wire the tested handler')
assert(index.includes('Deno.serve(handler)'), 'index must serve the composed handler')
assert(!index.includes('api.openai.com'), 'provider IO must live in openai-provider.ts')
})
Deno.test('provider checks and minting precede the quota spend', () => {
const configuredIndex = handler.indexOf('provider.isConfigured()')
const mintIndex = handler.indexOf('provider.mintClientSecret(', configuredIndex)
const consumeIndex = handler.indexOf('quota.consume(', mintIndex)
assert(configuredIndex >= 0, 'provider availability check missing')
assert(mintIndex > configuredIndex, 'minting must follow the availability check')
assert(consumeIndex > mintIndex, 'quota must be consumed only after a successful mint')
})
Deno.test('raw provider and exception text are never returned', () => {
for (const source of [index, handler, provider]) {
assert(!source.includes('JSON.stringify({ error: message })'), 'raw exception message returned')
assert(!source.includes('errText'), 'provider error body is read into the response path')
}
assert(handler.includes("json(500, { error: 'internal_error' })"), 'generic internal error missing')
})