vite-plugin-react-server
Version:
Vite plugin for React Server Components (RSC)
189 lines (186 loc) • 21.6 kB
JavaScript
/**
* vite-plugin-react-server
* Copyright (c) Nico Brinkkemper
* MIT License
*/
import { ReactDOMServer } from '../vendor/vendor.client.js';
import { assertNonReactServer } from '../config/getCondition.js';
import { createFromNodeStream } from './createFromNodeStream.client.js';
import { createStreamMetrics } from '../metrics/createStreamMetrics.js';
import { handleError } from '../error/handleError.js';
import { PassThrough } from 'node:stream';
assertNonReactServer();
const createRenderToPipeableStreamHandler = function _createRenderToPipeableStreamHandler(options) {
const {
route,
logger,
verbose = false,
rscStream,
children,
moduleRootPath,
moduleBasePath,
moduleBaseURL,
clientPipeableStreamOptions
} = options;
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] Starting RSC-to-HTML conversion using natural Node.js streams`
);
}
const streamMetrics = createStreamMetrics();
let reactElements;
if (children) {
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] Using provided children directly`
);
}
if (typeof children === "string" || typeof children === "number" || typeof children === "boolean") {
throw new Error(`[createRenderToPipeableStreamHandler.client:${route}] Children must be a React element, got: ${typeof children}`);
}
reactElements = children;
} else if (rscStream) {
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] Converting RSC stream to React elements using natural Node.js streams`
);
}
const result = createFromNodeStream({
rscStream,
moduleRootPath,
moduleBasePath,
moduleBaseURL,
logger,
verbose
});
reactElements = result.children;
} else {
throw new Error(
`[createRenderToPipeableStreamHandler.client:${route}] Either children or rscStream is required`
);
}
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] React elements ready, starting HTML rendering`
);
}
const { pipe, abort } = ReactDOMServer.renderToPipeableStream(reactElements, {
bootstrapModules: clientPipeableStreamOptions?.bootstrapModules || [],
onShellReady() {
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] Shell ready, starting to pipe HTML`
);
}
},
onAllReady() {
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] All ready, HTML rendering complete`
);
}
},
onError(error) {
if (verbose) {
logger?.error(
`[createRenderToPipeableStreamHandler.client:${route}] React rendering error: ${error instanceof Error ? error.message : String(error)}`
);
}
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] Destroying HTML stream due to React error`
);
}
htmlStream.destroy(error instanceof Error ? error : new Error(String(error)));
const panicError = handleError({
error,
logger,
panicThreshold: options.panicThreshold});
if (panicError != null) {
options.onEvent?.({
type: "route.error",
data: {
route,
error: panicError
}
});
} else {
options.onEvent?.({
type: "route.error",
data: {
route,
error
}
});
}
}
});
const htmlStream = new PassThrough();
htmlStream.on("error", (error) => {
if (verbose) {
logger?.info(`[createRenderToPipeableStreamHandler.client:${route}] HTML stream error (ignored): ${error.message}`);
}
});
const customWritable = {
write(chunk, _encoding, callback) {
htmlStream.write(chunk);
if (callback) callback();
},
end(chunk, _encoding, callback) {
if (chunk) {
htmlStream.write(chunk);
}
htmlStream.end();
if (callback) callback();
},
destroy(error) {
try {
htmlStream.destroy(error);
} catch (destroyError) {
}
},
on() {
},
// No-op for event listeners
once() {
},
// No-op for event listeners
emit() {
return false;
}
// No-op for event emitters
};
pipe(customWritable);
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] React stream piped to custom writable, using natural Node.js stream handling`
);
}
return {
type: "client",
pipe: (destination) => {
htmlStream.pipe(destination);
return destination;
},
abort: (reason) => {
try {
abort();
} catch (error) {
}
try {
htmlStream.destroy(new Error(String(reason || "Aborted HTML stream")));
} catch (error) {
}
if (verbose) {
logger?.info(
`[createRenderToPipeableStreamHandler.client:${route}] HTML stream aborted: ${reason}`
);
}
},
htmlStream,
elements: reactElements,
metrics: streamMetrics
};
};
export { createRenderToPipeableStreamHandler };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlUmVuZGVyVG9QaXBlYWJsZVN0cmVhbUhhbmRsZXIuY2xpZW50LmpzIiwic291cmNlcyI6WyIuLi8uLi8uLi9wbHVnaW4vc3RyZWFtL2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IENyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyRm4gfSBmcm9tIFwiLi9jcmVhdGVSZW5kZXJUb1BpcGVhYmxlU3RyZWFtSGFuZGxlci50eXBlcy5qc1wiO1xuaW1wb3J0IHsgUmVhY3RET01TZXJ2ZXIgfSBmcm9tIFwiLi4vdmVuZG9yL3ZlbmRvci5jbGllbnQuanNcIjtcbmltcG9ydCB7IGFzc2VydE5vblJlYWN0U2VydmVyIH0gZnJvbSBcIi4uL2NvbmZpZy9nZXRDb25kaXRpb24uanNcIjtcbmltcG9ydCB7IGNyZWF0ZUZyb21Ob2RlU3RyZWFtIH0gZnJvbSBcIi4vY3JlYXRlRnJvbU5vZGVTdHJlYW0uY2xpZW50LmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVTdHJlYW1NZXRyaWNzIH0gZnJvbSBcIi4uL21ldHJpY3MvY3JlYXRlU3RyZWFtTWV0cmljcy5qc1wiO1xuaW1wb3J0IHsgaGFuZGxlRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3IvaGFuZGxlRXJyb3IuanNcIjtcbmltcG9ydCB7IFBhc3NUaHJvdWdoIH0gZnJvbSBcIm5vZGU6c3RyZWFtXCI7XG5cbmFzc2VydE5vblJlYWN0U2VydmVyKCk7XG5cbi8qKlxuICogQ2xpZW50IHZlcnNpb24gb2YgY3JlYXRlUmVuZGVyVG9QaXBlYWJsZVN0cmVhbUhhbmRsZXIuXG4gKlxuICogU3RyYXRlZ3k6IFVzZSBzaW1wbGUgTm9kZS5qcyBzdHJlYW0gQVBJcyB0byBuYXR1cmFsbHkgaGFuZGxlIFJTQy10by1IVE1MIGNvbnZlcnNpb24uXG4gKiBUaGlzIGZvbGxvd3MgdGhlIEhUTUwgd29ya2VyIHBhdHRlcm4gZXhhY3RseSAtIGNyZWF0ZSBhIGN1c3RvbSB3cml0YWJsZSBzdHJlYW1cbiAqIGFuZCBwaXBlIHRoZSBSZWFjdCBzdHJlYW0gZGlyZWN0bHkgdG8gaXQsIHRoZW4gcHJvdmlkZSBhIHByb3BlciBzdHJlYW0gZm9yIGZpbGVXcml0ZXIuXG4gKi9cbmV4cG9ydCBjb25zdCBjcmVhdGVSZW5kZXJUb1BpcGVhYmxlU3RyZWFtSGFuZGxlcjogQ3JlYXRlUmVuZGVyVG9QaXBlYWJsZVN0cmVhbUhhbmRsZXJGbjxcImNsaWVudFwiPiA9XG4gIGZ1bmN0aW9uIF9jcmVhdGVSZW5kZXJUb1BpcGVhYmxlU3RyZWFtSGFuZGxlcihvcHRpb25zKSB7XG4gICAgY29uc3Qge1xuICAgICAgcm91dGUsXG4gICAgICBsb2dnZXIsXG4gICAgICB2ZXJib3NlID0gZmFsc2UsXG4gICAgICByc2NTdHJlYW0sXG4gICAgICBjaGlsZHJlbixcbiAgICAgIG1vZHVsZVJvb3RQYXRoLFxuICAgICAgbW9kdWxlQmFzZVBhdGgsXG4gICAgICBtb2R1bGVCYXNlVVJMLFxuICAgICAgY2xpZW50UGlwZWFibGVTdHJlYW1PcHRpb25zLFxuICAgIH0gPSBvcHRpb25zO1xuXG4gICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgIGxvZ2dlcj8uaW5mbyhcbiAgICAgICAgYFtjcmVhdGVSZW5kZXJUb1BpcGVhYmxlU3RyZWFtSGFuZGxlci5jbGllbnQ6JHtyb3V0ZX1dIFN0YXJ0aW5nIFJTQy10by1IVE1MIGNvbnZlcnNpb24gdXNpbmcgbmF0dXJhbCBOb2RlLmpzIHN0cmVhbXNgXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENyZWF0ZSBzdHJlYW0gbWV0cmljc1xuICAgIGNvbnN0IHN0cmVhbU1ldHJpY3MgPSBjcmVhdGVTdHJlYW1NZXRyaWNzKCk7XG5cbiAgICAvLyBHZXQgUmVhY3QgZWxlbWVudHMgLSBlaXRoZXIgZnJvbSBjaGlsZHJlbiBvciBieSBjb252ZXJ0aW5nIFJTQyBzdHJlYW1cbiAgICBsZXQgcmVhY3RFbGVtZW50czogUmVhY3QuUmVhY3RFbGVtZW50O1xuICAgIGlmIChjaGlsZHJlbikge1xuICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICAgIGBbY3JlYXRlUmVuZGVyVG9QaXBlYWJsZVN0cmVhbUhhbmRsZXIuY2xpZW50OiR7cm91dGV9XSBVc2luZyBwcm92aWRlZCBjaGlsZHJlbiBkaXJlY3RseWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIC8vIEVuc3VyZSBjaGlsZHJlbiBpcyBhIFJlYWN0IGVsZW1lbnRcbiAgICAgIGlmICh0eXBlb2YgY2hpbGRyZW4gPT09ICdzdHJpbmcnIHx8IHR5cGVvZiBjaGlsZHJlbiA9PT0gJ251bWJlcicgfHwgdHlwZW9mIGNoaWxkcmVuID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbY3JlYXRlUmVuZGVyVG9QaXBlYWJsZVN0cmVhbUhhbmRsZXIuY2xpZW50OiR7cm91dGV9XSBDaGlsZHJlbiBtdXN0IGJlIGEgUmVhY3QgZWxlbWVudCwgZ290OiAke3R5cGVvZiBjaGlsZHJlbn1gKTtcbiAgICAgIH1cbiAgICAgIHJlYWN0RWxlbWVudHMgPSBjaGlsZHJlbiBhcyBSZWFjdC5SZWFjdEVsZW1lbnQ7XG4gICAgfSBlbHNlIGlmIChyc2NTdHJlYW0pIHtcbiAgICAgIGlmICh2ZXJib3NlKSB7XG4gICAgICAgIGxvZ2dlcj8uaW5mbyhcbiAgICAgICAgICBgW2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudDoke3JvdXRlfV0gQ29udmVydGluZyBSU0Mgc3RyZWFtIHRvIFJlYWN0IGVsZW1lbnRzIHVzaW5nIG5hdHVyYWwgTm9kZS5qcyBzdHJlYW1zYFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVzdWx0ID0gY3JlYXRlRnJvbU5vZGVTdHJlYW0oe1xuICAgICAgICByc2NTdHJlYW0sXG4gICAgICAgIG1vZHVsZVJvb3RQYXRoLFxuICAgICAgICBtb2R1bGVCYXNlUGF0aCxcbiAgICAgICAgbW9kdWxlQmFzZVVSTCxcbiAgICAgICAgbG9nZ2VyLFxuICAgICAgICB2ZXJib3NlLFxuICAgICAgfSk7XG4gICAgICByZWFjdEVsZW1lbnRzID0gcmVzdWx0LmNoaWxkcmVuO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBbY3JlYXRlUmVuZGVyVG9QaXBlYWJsZVN0cmVhbUhhbmRsZXIuY2xpZW50OiR7cm91dGV9XSBFaXRoZXIgY2hpbGRyZW4gb3IgcnNjU3RyZWFtIGlzIHJlcXVpcmVkYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAodmVyYm9zZSkge1xuICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICBgW2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudDoke3JvdXRlfV0gUmVhY3QgZWxlbWVudHMgcmVhZHksIHN0YXJ0aW5nIEhUTUwgcmVuZGVyaW5nYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgdGhlIFJlYWN0IEhUTUwgc3RyZWFtIHVzaW5nIFJlYWN0RE9NU2VydmVyLnJlbmRlclRvUGlwZWFibGVTdHJlYW1cbiAgICBjb25zdCB7IHBpcGUsIGFib3J0IH0gPSBSZWFjdERPTVNlcnZlci5yZW5kZXJUb1BpcGVhYmxlU3RyZWFtKHJlYWN0RWxlbWVudHMsIHtcbiAgICAgIGJvb3RzdHJhcE1vZHVsZXM6XG4gICAgICAgIGNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucz8uYm9vdHN0cmFwTW9kdWxlcyB8fCBbXSxcbiAgICAgIG9uU2hlbGxSZWFkeSgpIHtcbiAgICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oXG4gICAgICAgICAgICBgW2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudDoke3JvdXRlfV0gU2hlbGwgcmVhZHksIHN0YXJ0aW5nIHRvIHBpcGUgSFRNTGBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgb25BbGxSZWFkeSgpIHtcbiAgICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oXG4gICAgICAgICAgICBgW2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudDoke3JvdXRlfV0gQWxsIHJlYWR5LCBIVE1MIHJlbmRlcmluZyBjb21wbGV0ZWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgb25FcnJvcihlcnJvcjogdW5rbm93bikge1xuICAgICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlcj8uZXJyb3IoXG4gICAgICAgICAgICBgW2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudDoke3JvdXRlfV0gUmVhY3QgcmVuZGVyaW5nIGVycm9yOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gRGVzdHJveSB0aGUgSFRNTCBzdHJlYW0gd2l0aCB0aGUgZXJyb3IgdG8gcHJldmVudCBoYW5naW5nXG4gICAgICAgIGlmICh2ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICAgICAgYFtjcmVhdGVSZW5kZXJUb1BpcGVhYmxlU3RyZWFtSGFuZGxlci5jbGllbnQ6JHtyb3V0ZX1dIERlc3Ryb3lpbmcgSFRNTCBzdHJlYW0gZHVlIHRvIFJlYWN0IGVycm9yYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaHRtbFN0cmVhbS5kZXN0cm95KGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSk7XG4gICAgICAgIFxuICAgICAgICAvLyBIYW5kbGUgZXJyb3IgYWNjb3JkaW5nIHRvIHBhbmljIHRocmVzaG9sZFxuICAgICAgICBjb25zdCBwYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgIGVycm9yOiBlcnJvcixcbiAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICBwYW5pY1RocmVzaG9sZDogb3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgICAgICBjb250ZXh0OiBgUlNDIHN0cmVhbSBvbkVycm9yIGZvciByb3V0ZSAke3JvdXRlfWAsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChwYW5pY0Vycm9yICE9IG51bGwpIHtcbiAgICAgICAgICAvLyBUaGlzIGlzIGEgcGFuaWMgdGhyZXNob2xkIGVycm9yLCBlbWl0IGV2ZW50IHRvIG5vdGlmeSBwYXJlbnRcbiAgICAgICAgICBvcHRpb25zLm9uRXZlbnQ/Lih7XG4gICAgICAgICAgICB0eXBlOiBcInJvdXRlLmVycm9yXCIsXG4gICAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAgIHJvdXRlOiByb3V0ZSxcbiAgICAgICAgICAgICAgZXJyb3I6IHBhbmljRXJyb3IsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIEZvciBub24tcGFuaWMgZXJyb3JzLCBqdXN0IGxvZyBhbmQgc2VuZCBldmVudFxuICAgICAgICAgIG9wdGlvbnMub25FdmVudD8uKHtcbiAgICAgICAgICAgIHR5cGU6IFwicm91dGUuZXJyb3JcIixcbiAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgcm91dGU6IHJvdXRlLFxuICAgICAgICAgICAgICBlcnJvcjogZXJyb3IsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gQ3JlYXRlIGEgUGFzc1Rocm91Z2ggc3RyZWFtIHRoYXQgdGhlIGZpbGVXcml0ZXIgY2FuIGNvbnN1bWVcbiAgICAvLyBUaGlzIGZvbGxvd3MgdGhlIEhUTUwgd29ya2VyIHBhdHRlcm4gYnV0IHByb3ZpZGVzIGEgcHJvcGVyIHN0cmVhbSBpbnRlcmZhY2VcbiAgICBjb25zdCBodG1sU3RyZWFtID0gbmV3IFBhc3NUaHJvdWdoKCk7XG4gICAgXG4gICAgLy8gQWRkIGVycm9yIGhhbmRsZXIgdG8gcHJldmVudCB1bmhhbmRsZWQgZXJyb3JzXG4gICAgaHRtbFN0cmVhbS5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgIC8vIElnbm9yZSBlcnJvcnMgZHVyaW5nIGFib3J0IC0gdGhleSdyZSBleHBlY3RlZFxuICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgbG9nZ2VyPy5pbmZvKGBbY3JlYXRlUmVuZGVyVG9QaXBlYWJsZVN0cmVhbUhhbmRsZXIuY2xpZW50OiR7cm91dGV9XSBIVE1MIHN0cmVhbSBlcnJvciAoaWdub3JlZCk6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIENyZWF0ZSBhIGN1c3RvbSB3cml0YWJsZSBzdHJlYW0gdGhhdCBwaXBlcyB0byBvdXIgUGFzc1Rocm91Z2hcbiAgICAvLyBUaGlzIGVuc3VyZXMgdGhlIHN0cmVhbSBpcyBjb25zdW1lZCB0byBjb21wbGV0aW9uIG5hdHVyYWxseVxuICAgIGNvbnN0IGN1c3RvbVdyaXRhYmxlID0ge1xuICAgICAgd3JpdGUoY2h1bms6IGFueSwgX2VuY29kaW5nPzogYW55LCBjYWxsYmFjaz86IGFueSkge1xuICAgICAgICAvLyBQaXBlIHRoZSBjaHVuayB0byBvdXIgUGFzc1Rocm91Z2ggc3RyZWFtXG4gICAgICAgIGh0bWxTdHJlYW0ud3JpdGUoY2h1bmspO1xuICAgICAgICBpZiAoY2FsbGJhY2spIGNhbGxiYWNrKCk7XG4gICAgICB9LFxuICAgICAgZW5kKGNodW5rPzogYW55LCBfZW5jb2Rpbmc/OiBhbnksIGNhbGxiYWNrPzogYW55KSB7XG4gICAgICAgIGlmIChjaHVuaykge1xuICAgICAgICAgIGh0bWxTdHJlYW0ud3JpdGUoY2h1bmspO1xuICAgICAgICB9XG4gICAgICAgIC8vIEVuZCB0aGUgUGFzc1Rocm91Z2ggc3RyZWFtXG4gICAgICAgIGh0bWxTdHJlYW0uZW5kKCk7XG4gICAgICAgIGlmIChjYWxsYmFjaykgY2FsbGJhY2soKTtcbiAgICAgIH0sXG4gICAgICBkZXN0cm95KGVycm9yPzogRXJyb3IpIHtcbiAgICAgICAgLy8gRGVzdHJveSB0aGUgUGFzc1Rocm91Z2ggc3RyZWFtIHdpdGggdGhlIGVycm9yXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaHRtbFN0cmVhbS5kZXN0cm95KGVycm9yKTtcbiAgICAgICAgfSBjYXRjaCAoZGVzdHJveUVycm9yKSB7XG4gICAgICAgICAgLy8gU3RyZWFtIG1heSBhbHJlYWR5IGJlIGRlc3Ryb3llZCwgaWdub3JlXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBvbigpIHt9LCAvLyBOby1vcCBmb3IgZXZlbnQgbGlzdGVuZXJzXG4gICAgICBvbmNlKCkge30sIC8vIE5vLW9wIGZvciBldmVudCBsaXN0ZW5lcnNcbiAgICAgIGVtaXQoKSB7IHJldHVybiBmYWxzZTsgfSwgLy8gTm8tb3AgZm9yIGV2ZW50IGVtaXR0ZXJzXG4gICAgfTtcblxuICAgIC8vIFBpcGUgdGhlIFJlYWN0IHN0cmVhbSBkaXJlY3RseSB0byBvdXIgY3VzdG9tIHdyaXRhYmxlXG4gICAgLy8gVGhpcyBlbnN1cmVzIHRoZSBzdHJlYW0gaXMgY29uc3VtZWQgdG8gY29tcGxldGlvbiBuYXR1cmFsbHlcbiAgICBwaXBlKGN1c3RvbVdyaXRhYmxlIGFzIGFueSk7XG5cbiAgICBpZiAodmVyYm9zZSkge1xuICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICBgW2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudDoke3JvdXRlfV0gUmVhY3Qgc3RyZWFtIHBpcGVkIHRvIGN1c3RvbSB3cml0YWJsZSwgdXNpbmcgbmF0dXJhbCBOb2RlLmpzIHN0cmVhbSBoYW5kbGluZ2BcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJuIGEgcmVzdWx0IHRoYXQgcHJvdmlkZXMgYSBwcm9wZXIgc3RyZWFtIGZvciBmaWxlV3JpdGVyXG4gICAgcmV0dXJuIHtcbiAgICAgIHR5cGU6IFwiY2xpZW50XCIgYXMgY29uc3QsXG4gICAgICBwaXBlOiA8V3JpdGFibGUgZXh0ZW5kcyBOb2RlSlMuV3JpdGFibGVTdHJlYW0+KGRlc3RpbmF0aW9uOiBXcml0YWJsZSkgPT4ge1xuICAgICAgICAvLyBQaXBlIG91ciBQYXNzVGhyb3VnaCBzdHJlYW0gdG8gdGhlIGRlc3RpbmF0aW9uXG4gICAgICAgIGh0bWxTdHJlYW0ucGlwZShkZXN0aW5hdGlvbik7XG4gICAgICAgIHJldHVybiBkZXN0aW5hdGlvbjtcbiAgICAgIH0sXG4gICAgICBhYm9ydDogKHJlYXNvbj86IHVua25vd24pID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIC8vIFJlYWN0IGFib3J0IG1heSBhbHJlYWR5IGJlIGNhbGxlZCwgaWdub3JlXG4gICAgICAgIH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBodG1sU3RyZWFtLmRlc3Ryb3kobmV3IEVycm9yKFN0cmluZyhyZWFzb24gfHwgXCJBYm9ydGVkIEhUTUwgc3RyZWFtXCIpKSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgLy8gU3RyZWFtIG1heSBhbHJlYWR5IGJlIGRlc3Ryb3llZCwgaWdub3JlXG4gICAgICAgIH1cbiAgICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oXG4gICAgICAgICAgICBgW2NyZWF0ZVJlbmRlclRvUGlwZWFibGVTdHJlYW1IYW5kbGVyLmNsaWVudDoke3JvdXRlfV0gSFRNTCBzdHJlYW0gYWJvcnRlZDogJHtyZWFzb259YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBodG1sU3RyZWFtOiBodG1sU3RyZWFtLFxuICAgICAgZWxlbWVudHM6IHJlYWN0RWxlbWVudHMsXG4gICAgICBtZXRyaWNzOiBzdHJlYW1NZXRyaWNzLFxuICAgIH07XG4gIH07XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBUUEsb0JBQXFCLEVBQUE7QUFTUixNQUFBLG1DQUFBLEdBQ1gsU0FBUyxvQ0FBQSxDQUFxQyxPQUFTLEVBQUE7QUFDckQsRUFBTSxNQUFBO0FBQUEsSUFDSixLQUFBO0FBQUEsSUFDQSxNQUFBO0FBQUEsSUFDQSxPQUFVLEdBQUEsS0FBQTtBQUFBLElBQ1YsU0FBQTtBQUFBLElBQ0EsUUFBQTtBQUFBLElBQ0EsY0FBQTtBQUFBLElBQ0EsY0FBQTtBQUFBLElBQ0EsYUFBQTtBQUFBLElBQ0E7QUFBQSxHQUNFLEdBQUEsT0FBQTtBQUVKLEVBQUEsSUFBSSxPQUFTLEVBQUE7QUFDWCxJQUFRLE1BQUEsRUFBQSxJQUFBO0FBQUEsTUFDTiwrQ0FBK0MsS0FBSyxDQUFBLCtEQUFBO0FBQUEsS0FDdEQ7QUFBQTtBQUlGLEVBQUEsTUFBTSxnQkFBZ0IsbUJBQW9CLEVBQUE7QUFHMUMsRUFBSSxJQUFBLGFBQUE7QUFDSixFQUFBLElBQUksUUFBVSxFQUFBO0FBQ1osSUFBQSxJQUFJLE9BQVMsRUFBQTtBQUNYLE1BQVEsTUFBQSxFQUFBLElBQUE7QUFBQSxRQUNOLCtDQUErQyxLQUFLLENBQUEsa0NBQUE7QUFBQSxPQUN0RDtBQUFBO0FBR0YsSUFBSSxJQUFBLE9BQU8sYUFBYSxRQUFZLElBQUEsT0FBTyxhQUFhLFFBQVksSUFBQSxPQUFPLGFBQWEsU0FBVyxFQUFBO0FBQ2pHLE1BQUEsTUFBTSxJQUFJLEtBQU0sQ0FBQSxDQUFBLDRDQUFBLEVBQStDLEtBQUssQ0FBNEMseUNBQUEsRUFBQSxPQUFPLFFBQVEsQ0FBRSxDQUFBLENBQUE7QUFBQTtBQUVuSSxJQUFnQixhQUFBLEdBQUEsUUFBQTtBQUFBLGFBQ1AsU0FBVyxFQUFBO0FBQ3BCLElBQUEsSUFBSSxPQUFTLEVBQUE7QUFDWCxN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