Don't hang if we can't make JSON.

Sometimes the route resolve functions will inadvertently produce something
we can't serialize as JSON, such as a circular data structure, or some
DOM elements. In this case we used to just get stuck, but now we'll
fail hard in that case so the developer can see what went wrong and
fix it.
Explicitly dispose the context when returning SDR responses.

It's important to dispose these or else we'll leak memory.
Fix the flattenPromises function to actually work.

The previous implementation would often terminate too quickly, before
all of the promises had been resolved. This new implementation works
in phases, collecting a bunch of promises and then waiting for them to
complete, and then possibly collecting some more and waiting for them,
and so on.