Closing shutdownCh lets main return and the runtime exit, which races
with makePromise invoking resolve, so the promise shutdown() hands back
may never settle. The JS loader already ignores it and awaits the
runtime's exit instead; say so here so the next reader does not take the
unsettled promise for a bug and rewire the callers.
Also note that the once and the channel now belong to the same instance.
webnet/webnet#206 left the shared-channel race to this branch, and the
one-IPN-per-runtime guard dissolves it.
Co-Authored-By: claude-opus-5 <noreply@anthropic.com>