44 lines
2.4 KiB
TypeScript
44 lines
2.4 KiB
TypeScript
// Source-level guards for the split stt-proxy (index.ts = composition root,
|
|
// handler.ts = use case, providers.ts = adapters). Behavior is covered by
|
|
// handler.test.ts and providers.test.ts; these checks keep the wiring honest.
|
|
const read = (file: string) => Deno.readTextFile(new URL(file, import.meta.url))
|
|
const [index, handler, providers] = await Promise.all([
|
|
read('./index.ts'),
|
|
read('./handler.ts'),
|
|
read('./providers.ts'),
|
|
])
|
|
const all = [index, handler, providers].join('\n')
|
|
|
|
function assert(condition: boolean, message: string): asserts condition {
|
|
if (!condition) throw new Error(message)
|
|
}
|
|
|
|
Deno.test('STT proxy has no synthetic success fallback', () => {
|
|
for (const forbidden of ['d3ro-cloud-mock', '음성 전사 완료', 'D3RO Cloud STT']) {
|
|
assert(!all.includes(forbidden), `forbidden synthetic fallback remains: ${forbidden}`)
|
|
}
|
|
assert(handler.includes("const error = status === 503 ? 'stt_provider_unavailable' : 'stt_upstream_failed'"),
|
|
'provider failures must produce an explicit 502/503 error')
|
|
})
|
|
|
|
Deno.test('gateway uses a dedicated D3RO API token', () => {
|
|
assert(index.includes("gatewayToken: Deno.env.get('D3RO_API_TOKEN')"), 'dedicated backend token is required')
|
|
assert(providers.includes('if (config.gatewayUrl && config.gatewayToken)'), 'gateway must be skipped without its own token')
|
|
assert(!all.includes("req.headers.get('Authorization')"), 'Supabase user JWT must not be forwarded to D3RO API')
|
|
assert(providers.includes('createInternalSttGatewayUrl(config.url)'),
|
|
'quota-owning internal endpoint must use the canonical URL guard')
|
|
assert(providers.includes("'X-D3RO-STT-Gateway-Token': config.token"),
|
|
'dedicated token must use the internal gateway header')
|
|
})
|
|
|
|
Deno.test('index.ts is only the composition root', () => {
|
|
assert(index.includes('Deno.serve(createSttProxyHandler('), 'index must serve the injected handler')
|
|
assert(!index.includes('await fetch('), 'provider IO belongs in providers.ts')
|
|
assert(!index.includes('runSttChain'), 'fallback policy belongs in handler.ts')
|
|
})
|
|
|
|
Deno.test('attempts never carry raw exception messages', () => {
|
|
assert(!all.includes('err.message}`'), 'raw exception text must not be formatted into a response')
|
|
assert(!all.includes('JSON.stringify({ error: message })'), 'raw exception messages must not be returned')
|
|
assert(handler.includes("json(500, { error: 'internal_error' })"), 'generic internal error response is missing')
|
|
})
|