|
|
|
|
@ -2,7 +2,7 @@
|
|
|
|
|
/** @import { AsyncLocalStorage } from 'node:async_hooks' */
|
|
|
|
|
/** @import { RenderContext } from '#server' */
|
|
|
|
|
|
|
|
|
|
import { deferred } from '../shared/utils.js';
|
|
|
|
|
import { deferred, noop } from '../shared/utils.js';
|
|
|
|
|
import * as e from './errors.js';
|
|
|
|
|
|
|
|
|
|
/** @type {Promise<void> | null} */
|
|
|
|
|
@ -56,14 +56,26 @@ export async function with_render_context(fn) {
|
|
|
|
|
|
|
|
|
|
/** @type {AsyncLocalStorage<RenderContext | null> | null} */
|
|
|
|
|
let als = null;
|
|
|
|
|
/** @type {Promise<void> | null} */
|
|
|
|
|
let als_import = null;
|
|
|
|
|
|
|
|
|
|
export async function init_render_context() {
|
|
|
|
|
if (als !== null) return;
|
|
|
|
|
try {
|
|
|
|
|
// @ts-ignore -- we don't include node types in the production build
|
|
|
|
|
const { AsyncLocalStorage } = await import('node:async_hooks');
|
|
|
|
|
als = new AsyncLocalStorage();
|
|
|
|
|
} catch {}
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
|
*/
|
|
|
|
|
export function init_render_context() {
|
|
|
|
|
// It's important the right side of this assignment can run a maximum of one time
|
|
|
|
|
// otherwise it's possible for a very, very well-timed race condition to assign to `als`
|
|
|
|
|
// at the beginning of a render, and then another render to assign to it again, which causes
|
|
|
|
|
// the first render's second half to use a new instance of `als` which doesn't have its
|
|
|
|
|
// context anymore.
|
|
|
|
|
// @ts-ignore -- we don't include node types in the production build
|
|
|
|
|
als_import ??= import('node:async_hooks')
|
|
|
|
|
.then((hooks) => {
|
|
|
|
|
als = new hooks.AsyncLocalStorage();
|
|
|
|
|
})
|
|
|
|
|
.then(noop, noop);
|
|
|
|
|
return als_import;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this has to be a function because rollup won't treeshake it if it's a constant
|
|
|
|
|
|