vite-plugin-react-server
Version:
Vite plugin for React Server Components (RSC)
225 lines (222 loc) • 28.6 kB
JavaScript
/**
* vite-plugin-react-server
* Copyright (c) Nico Brinkkemper
* MIT License
*/
import { PassThrough } from 'node:stream';
import { createLogger } from 'vite';
import { createSerializableHandlerOptions } from '../helpers/createSerializableHandlerOptions.js';
import { toError } from '../error/toError.js';
import { serializeError } from '../error/serializeError.js';
import { createMessageChannels } from './createMessageChannels.js';
const createHtmlStream = function _createHtmlStream(options) {
const {
route,
id = route,
rscStream,
htmlWorker,
verbose = false,
logger = createLogger(),
onError,
panicThreshold
} = options;
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] Creating HTML stream with MessagePort`
);
}
if (!htmlWorker) {
throw new Error("HTML worker is required for server-side HTML streaming");
}
const { dataPort1, dataPort2, controlPort1, controlPort2 } = createMessageChannels();
const htmlStream = new PassThrough();
let isStreamEnded = false;
let chunkCount = 0;
let isHtmlStreamReady = true;
let pendingRscChunks = [];
const processPendingRscChunks = () => {
if (verbose && pendingRscChunks.length > 0) {
logger.info(
`[createHtmlStream.server:${route}] Processing ${pendingRscChunks.length} pending RSC chunks`
);
}
while (pendingRscChunks.length > 0 && isHtmlStreamReady && !isStreamEnded) {
const chunk = pendingRscChunks.shift();
try {
dataPort1.postMessage(chunk);
chunkCount++;
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] Processed pending RSC chunk ${chunkCount}`
);
}
} catch (error) {
pendingRscChunks.unshift(chunk);
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] Still backpressure, stopping processing`
);
}
break;
}
}
};
const sendChunk = (chunk) => {
if (!isStreamEnded && isHtmlStreamReady) {
try {
dataPort1.postMessage(chunk);
chunkCount++;
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] Sent chunk ${chunkCount}`
);
}
} catch (error) {
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] MessagePort backpressure detected, RSC stream will naturally slow down`
);
}
}
} else if (!isStreamEnded) {
pendingRscChunks.push(chunk);
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] HTML stream backpressured, buffering RSC chunk (${pendingRscChunks.length} pending)`
);
}
}
};
const dataMessageHandler = (event) => {
const data = event;
if (data === void 0) {
return;
}
if (data === null) {
if (verbose) {
logger.info(`[createHtmlStream.server:${route}] HTML stream ended by worker`);
}
htmlStream.end();
cleanup();
htmlWorker.postMessage({ type: "CLEANUP", id, route });
} else {
if (verbose) {
logger.info(`[createHtmlStream.server:${route}] Writing HTML chunk: ${data.length} bytes`);
}
if (htmlStream.destroyed || htmlStream.writableEnded) {
if (verbose) {
logger.info(`[createHtmlStream.server:${route}] HTML stream already ended, ignoring data chunk`);
}
return;
}
const canWrite = htmlStream.write(data);
if (!canWrite) {
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] HTML stream backpressured, pausing worker`
);
}
isHtmlStreamReady = false;
controlPort1.postMessage({ type: "PAUSE", id });
htmlStream.once("drain", () => {
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] HTML stream drained, resuming worker`
);
}
isHtmlStreamReady = true;
processPendingRscChunks();
controlPort1.postMessage({ type: "RESUME", id });
});
}
}
};
dataPort1.on("message", dataMessageHandler);
const controlMessageHandler = (event) => {
const message = event;
if (!message || typeof message !== "object") {
return;
}
switch (message.type) {
case "READY":
if (verbose) {
logger.info(`[createHtmlStream.server:${route}] HTML worker ready for more data`);
}
processPendingRscChunks();
break;
case "END":
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] Received END message, waiting for null data to confirm completion`
);
}
break;
case "ERROR":
const error = toError(message.error, message.errorInfo);
htmlStream.destroy(error);
if (onError) {
const isPanic = panicThreshold === "all_errors";
onError(error, isPanic);
}
cleanup();
htmlWorker.postMessage({ type: "CLEANUP", id, route });
break;
case "METRICS":
break;
case "HTML_RENDER_START":
break;
case "CLEANUP_COMPLETE":
if (verbose) {
logger.info(`[createHtmlStream.server:${route}] Worker cleanup completed for route ${message.id}`);
}
break;
}
};
controlPort1.on("message", controlMessageHandler);
htmlWorker.postMessage(
{
type: "INIT",
id: route,
dataPort: dataPort2,
controlPort: controlPort2,
options: createSerializableHandlerOptions(options)
},
[dataPort2, controlPort2]
);
if (rscStream) {
if (verbose) {
logger.info(
`[createHtmlStream.server:${route}] Piping RSC stream to HTML worker`
);
}
rscStream.on("data", (chunk) => {
sendChunk(chunk);
});
rscStream.on("end", () => {
isStreamEnded = true;
});
rscStream.on("error", (error) => {
const serializedError = serializeError(error);
controlPort1.postMessage({ type: "ERROR", error: serializedError });
dataPort1.postMessage({ error: serializedError });
});
}
const cleanup = () => {
try {
dataPort1.removeListener("message", dataMessageHandler);
controlPort1.removeListener("message", controlMessageHandler);
} catch (error) {
}
};
return {
pipe: (destination) => htmlStream.pipe(destination),
abort: () => {
controlPort1.postMessage({ type: "ABORT", reason: "Stream aborted" });
htmlStream.end();
cleanup();
htmlWorker.postMessage({ type: "CLEANUP", id, route });
}
};
};
export { createHtmlStream };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlSHRtbFN0cmVhbS5zZXJ2ZXIuanMiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3BsdWdpbi9zdHJlYW0vY3JlYXRlSHRtbFN0cmVhbS5zZXJ2ZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGFzc1Rocm91Z2ggfSBmcm9tIFwibm9kZTpzdHJlYW1cIjtcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gXCJ2aXRlXCI7XG5pbXBvcnQgdHlwZSB7IENyZWF0ZUh0bWxTdHJlYW1GbiB9IGZyb20gXCIuL2NyZWF0ZUh0bWxTdHJlYW0udHlwZXMuanNcIjtcbmltcG9ydCB7IGNyZWF0ZVNlcmlhbGl6YWJsZUhhbmRsZXJPcHRpb25zIH0gZnJvbSBcIi4uL2hlbHBlcnMvY3JlYXRlU2VyaWFsaXphYmxlSGFuZGxlck9wdGlvbnMuanNcIjtcbmltcG9ydCB7IHRvRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3IvdG9FcnJvci5qc1wiO1xuaW1wb3J0IHsgc2VyaWFsaXplRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3Ivc2VyaWFsaXplRXJyb3IuanNcIjtcbmltcG9ydCB7IGNyZWF0ZU1lc3NhZ2VDaGFubmVscyB9IGZyb20gXCIuL2NyZWF0ZU1lc3NhZ2VDaGFubmVscy5qc1wiO1xuLyoqXG4gKiBDcmVhdGVzIGFuIEhUTUwgc3RyZWFtIHVzaW5nIGEgTWVzc2FnZVBvcnQgZm9yIGRpcmVjdCBjb21tdW5pY2F0aW9uIHdpdGggdGhlIEhUTUwgd29ya2VyXG4gKi9cbmV4cG9ydCBjb25zdCBjcmVhdGVIdG1sU3RyZWFtOiBDcmVhdGVIdG1sU3RyZWFtRm4gPSBmdW5jdGlvbiBfY3JlYXRlSHRtbFN0cmVhbShcbiAgb3B0aW9uc1xuKSB7XG4gIGNvbnN0IHtcbiAgICByb3V0ZSxcbiAgICBpZCA9IHJvdXRlLFxuICAgIHJzY1N0cmVhbSxcbiAgICBodG1sV29ya2VyLFxuICAgIHZlcmJvc2UgPSBmYWxzZSxcbiAgICBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoKSxcbiAgICBvbkVycm9yLFxuICAgIHBhbmljVGhyZXNob2xkLFxuICB9ID0gb3B0aW9ucztcblxuICBpZiAodmVyYm9zZSkge1xuICAgIGxvZ2dlci5pbmZvKFxuICAgICAgYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gQ3JlYXRpbmcgSFRNTCBzdHJlYW0gd2l0aCBNZXNzYWdlUG9ydGBcbiAgICApO1xuICB9XG5cbiAgaWYgKCFodG1sV29ya2VyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiSFRNTCB3b3JrZXIgaXMgcmVxdWlyZWQgZm9yIHNlcnZlci1zaWRlIEhUTUwgc3RyZWFtaW5nXCIpO1xuICB9XG5cbiAgLy8gQ3JlYXRlIHR3byBzZXBhcmF0ZSBNZXNzYWdlUG9ydHMgZm9yIGNsZWFuIHNlcGFyYXRpb24gb2YgY29uY2VybnNcbiAgY29uc3QgeyBkYXRhUG9ydDEsIGRhdGFQb3J0MiwgY29udHJvbFBvcnQxLCBjb250cm9sUG9ydDIgfSA9IGNyZWF0ZU1lc3NhZ2VDaGFubmVscygpO1xuXG4gIC8vIENyZWF0ZSB0aGUgSFRNTCBvdXRwdXQgc3RyZWFtXG4gIGNvbnN0IGh0bWxTdHJlYW0gPSBuZXcgUGFzc1Rocm91Z2goKTtcblxuICAvLyBGbG93IGNvbnRyb2wgc3RhdGUgZm9yIEhUTUwgb3V0cHV0IHN0cmVhbSBiYWNrcHJlc3N1cmUgaGFuZGxpbmdcbiAgbGV0IGlzU3RyZWFtRW5kZWQgPSBmYWxzZTtcbiAgbGV0IGNodW5rQ291bnQgPSAwOyAvLyBUcmFjayBudW1iZXIgb2YgY2h1bmtzIHNlbnRcbiAgbGV0IGlzSHRtbFN0cmVhbVJlYWR5ID0gdHJ1ZTsgLy8gVHJhY2sgaWYgSFRNTCBzdHJlYW0gY2FuIGFjY2VwdCBtb3JlIGRhdGFcbiAgbGV0IHBlbmRpbmdSc2NDaHVua3M6IGFueVtdID0gW107IC8vIEJ1ZmZlciBmb3IgUlNDIGNodW5rcyB3aGVuIEhUTUwgc3RyZWFtIGlzIGJhY2twcmVzc3VyZWRcbiAgLy8gTm8gbmVlZCB0byB0cmFjayBFTkQgbWVzc2FnZSBzdGF0ZSAtIHJlbHkgb24gbnVsbCBkYXRhIG1lc3NhZ2UgZm9yIGNvbXBsZXRpb25cblxuICAvLyBGdW5jdGlvbiB0byBwcm9jZXNzIHBlbmRpbmcgUlNDIGNodW5rcyB3aGVuIEhUTUwgc3RyZWFtIGJlY29tZXMgcmVhZHlcbiAgY29uc3QgcHJvY2Vzc1BlbmRpbmdSc2NDaHVua3MgPSAoKSA9PiB7XG4gICAgaWYgKHZlcmJvc2UgJiYgcGVuZGluZ1JzY0NodW5rcy5sZW5ndGggPiAwKSB7XG4gICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gUHJvY2Vzc2luZyAke3BlbmRpbmdSc2NDaHVua3MubGVuZ3RofSBwZW5kaW5nIFJTQyBjaHVua3NgXG4gICAgICApO1xuICAgIH1cblxuICAgIHdoaWxlIChwZW5kaW5nUnNjQ2h1bmtzLmxlbmd0aCA+IDAgJiYgaXNIdG1sU3RyZWFtUmVhZHkgJiYgIWlzU3RyZWFtRW5kZWQpIHtcbiAgICAgIGNvbnN0IGNodW5rID0gcGVuZGluZ1JzY0NodW5rcy5zaGlmdCgpITtcbiAgICAgIHRyeSB7XG4gICAgICAgIGRhdGFQb3J0MS5wb3N0TWVzc2FnZShjaHVuayk7XG4gICAgICAgIGNodW5rQ291bnQrKztcbiAgICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbY3JlYXRlSHRtbFN0cmVhbS5zZXJ2ZXI6JHtyb3V0ZX1dIFByb2Nlc3NlZCBwZW5kaW5nIFJTQyBjaHVuayAke2NodW5rQ291bnR9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIC8vIFN0aWxsIGJhY2twcmVzc3VyZSwgcHV0IGNodW5rIGJhY2sgYW5kIHN0b3BcbiAgICAgICAgcGVuZGluZ1JzY0NodW5rcy51bnNoaWZ0KGNodW5rKTtcbiAgICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbY3JlYXRlSHRtbFN0cmVhbS5zZXJ2ZXI6JHtyb3V0ZX1dIFN0aWxsIGJhY2twcmVzc3VyZSwgc3RvcHBpbmcgcHJvY2Vzc2luZ2BcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICAvLyBGdW5jdGlvbiB0byBzZW5kIGEgY2h1bmsgdG8gdGhlIHdvcmtlclxuICAvLyBDaGVjayBpZiBIVE1MIHN0cmVhbSBpcyByZWFkeSBiZWZvcmUgc2VuZGluZyBSU0MgY2h1bmtzXG4gIGNvbnN0IHNlbmRDaHVuayA9IChjaHVuazogYW55KSA9PiB7XG4gICAgaWYgKCFpc1N0cmVhbUVuZGVkICYmIGlzSHRtbFN0cmVhbVJlYWR5KSB7XG4gICAgICB0cnkge1xuICAgICAgICBkYXRhUG9ydDEucG9zdE1lc3NhZ2UoY2h1bmspO1xuICAgICAgICBjaHVua0NvdW50Kys7XG4gICAgICAgIGlmICh2ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oXG4gICAgICAgICAgICBgW2NyZWF0ZUh0bWxTdHJlYW0uc2VydmVyOiR7cm91dGV9XSBTZW50IGNodW5rICR7Y2h1bmtDb3VudH1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gTWVzc2FnZVBvcnQgZXJyb3IgLSB0aGlzIHdpbGwgbmF0dXJhbGx5IGJhY2twcmVzc3VyZSB0aGUgUlNDIHN0cmVhbVxuICAgICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gTWVzc2FnZVBvcnQgYmFja3ByZXNzdXJlIGRldGVjdGVkLCBSU0Mgc3RyZWFtIHdpbGwgbmF0dXJhbGx5IHNsb3cgZG93bmBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICghaXNTdHJlYW1FbmRlZCkge1xuICAgICAgLy8gSFRNTCBzdHJlYW0gaXMgYmFja3ByZXNzdXJlZCwgYnVmZmVyIHRoaXMgUlNDIGNodW5rXG4gICAgICBwZW5kaW5nUnNjQ2h1bmtzLnB1c2goY2h1bmspO1xuICAgICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oXG4gICAgICAgICAgYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gSFRNTCBzdHJlYW0gYmFja3ByZXNzdXJlZCwgYnVmZmVyaW5nIFJTQyBjaHVuayAoJHtwZW5kaW5nUnNjQ2h1bmtzLmxlbmd0aH0gcGVuZGluZylgXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIC8vIERhdGEgcG9ydCAtIHJlY2VpdmVzIEhUTUwgZGF0YSBmcm9tIHdvcmtlclxuICBjb25zdCBkYXRhTWVzc2FnZUhhbmRsZXIgPSAoZXZlbnQ6IGFueSkgPT4ge1xuICAgIGlmICh2ZXJib3NlKSB7XG4gICAgfVxuICAgIGNvbnN0IGRhdGEgPSBldmVudDsgLy8gTWVzc2FnZVBvcnQgZXZlbnRzIGNvbnRhaW4gdGhlIGRhdGEgZGlyZWN0bHlcbiAgICBcbiAgICBpZiAoZGF0YSA9PT0gdW5kZWZpbmVkKSB7XG5cbiAgICAgIHJldHVybjsgLy8gSWdub3JlIHVuZGVmaW5lZCBtZXNzYWdlc1xuICAgIH1cblxuICAgIGlmIChkYXRhID09PSBudWxsKSB7XG4gICAgICAvLyBFbmQgb2Ygc3RyZWFtXG4gICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICBsb2dnZXIuaW5mbyhgW2NyZWF0ZUh0bWxTdHJlYW0uc2VydmVyOiR7cm91dGV9XSBIVE1MIHN0cmVhbSBlbmRlZCBieSB3b3JrZXJgKTtcbiAgICAgIH1cbiAgICAgIGh0bWxTdHJlYW0uZW5kKCk7XG5cbiAgICAgIC8vIENsZWFuIHVwIGxpc3RlbmVycyBhbmQgY2xvc2UgcG9ydHMgd2hlbiBzdHJlYW0gZW5kcyBuYXR1cmFsbHlcbiAgICAgIGNsZWFudXAoKTtcblxuICAgICAgLy8gU2VuZCBjbGVhbnVwIG1lc3NhZ2UgdG8gd29ya2VyIHRvIHJlc2V0IGl0cyBpbnRlcm5hbCBzdGF0ZVxuICAgICAgLy8gVGhpcyBwcmV2ZW50cyByYWNlIGNvbmRpdGlvbnMgYmV0d2VlbiBwYWdlIHJlbmRlcnNcbiAgICAgIGh0bWxXb3JrZXIucG9zdE1lc3NhZ2UoeyB0eXBlOiBcIkNMRUFOVVBcIiwgaWQ6IGlkLCByb3V0ZTogcm91dGUgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFJhdyBIVE1MIGRhdGEgZnJvbSB3b3JrZXIgLSB3cml0ZSB0byBzdHJlYW1cbiAgICAgIGlmICh2ZXJib3NlKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKGBbY3JlYXRlSHRtbFN0cmVhbS5zZXJ2ZXI6JHtyb3V0ZX1dIFdyaXRpbmcgSFRNTCBjaHVuazogJHtkYXRhLmxlbmd0aH0gYnl0ZXNgKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIEhUTUwgc3RyZWFtIGlzIHN0aWxsIHdyaXRhYmxlIGJlZm9yZSBhdHRlbXB0aW5nIHRvIHdyaXRlXG4gICAgICBpZiAoaHRtbFN0cmVhbS5kZXN0cm95ZWQgfHwgaHRtbFN0cmVhbS53cml0YWJsZUVuZGVkKSB7XG4gICAgICAgIGlmICh2ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gSFRNTCBzdHJlYW0gYWxyZWFkeSBlbmRlZCwgaWdub3JpbmcgZGF0YSBjaHVua2ApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgLy8gRGF0YSByZWNlaXZlZCAtIHN0cmVhbSBpcyBzdGlsbCBhY3RpdmVcblxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIEhUTUwgc3RyZWFtIGNhbiBhY2NlcHQgbW9yZSBkYXRhIChiYWNrcHJlc3N1cmUgaGFuZGxpbmcpXG4gICAgICBjb25zdCBjYW5Xcml0ZSA9IGh0bWxTdHJlYW0ud3JpdGUoZGF0YSk7XG5cbiAgICAgIGlmICghY2FuV3JpdGUpIHtcbiAgICAgICAgLy8gSFRNTCBzdHJlYW0gaXMgYmFja3ByZXNzdXJlZCwgcGF1c2UgdGhlIHdvcmtlclxuICAgICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gSFRNTCBzdHJlYW0gYmFja3ByZXNzdXJlZCwgcGF1c2luZyB3b3JrZXJgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBpc0h0bWxTdHJlYW1SZWFkeSA9IGZhbHNlO1xuICAgICAgICBcbiAgICAgICAgLy8gVGVsbCB0aGUgd29ya2VyIHRvIHBhdXNlIHNlbmRpbmcgbW9yZSBkYXRhXG4gICAgICAgIGNvbnRyb2xQb3J0MS5wb3N0TWVzc2FnZSh7IHR5cGU6IFwiUEFVU0VcIiwgaWQ6IGlkIH0pO1xuXG4gICAgICAgIC8vIExpc3RlbiBmb3IgZHJhaW4gZXZlbnQgdG8gcmVzdW1lXG4gICAgICAgIGh0bWxTdHJlYW0ub25jZShcImRyYWluXCIsICgpID0+IHtcbiAgICAgICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICAgICAgbG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgIGBbY3JlYXRlSHRtbFN0cmVhbS5zZXJ2ZXI6JHtyb3V0ZX1dIEhUTUwgc3RyZWFtIGRyYWluZWQsIHJlc3VtaW5nIHdvcmtlcmBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlzSHRtbFN0cmVhbVJlYWR5ID0gdHJ1ZTtcbiAgICAgICAgICAvLyBQcm9jZXNzIGFueSBwZW5kaW5nIFJTQyBjaHVua3MgZmlyc3RcbiAgICAgICAgICBwcm9jZXNzUGVuZGluZ1JzY0NodW5rcygpO1xuICAgICAgICAgIC8vIFRlbGwgd29ya2VyIGl0IGNhbiByZXN1bWUgc2VuZGluZyBkYXRhXG4gICAgICAgICAgY29udHJvbFBvcnQxLnBvc3RNZXNzYWdlKHsgdHlwZTogXCJSRVNVTUVcIiwgaWQ6IGlkIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIFxuICAgIH1cbiAgfTtcbiAgXG4gIGRhdGFQb3J0MS5vbignbWVzc2FnZScsIGRhdGFNZXNzYWdlSGFuZGxlcik7XG5cbiAgLy8gQ29udHJvbCBwb3J0XG4gIGNvbnN0IGNvbnRyb2xNZXNzYWdlSGFuZGxlciA9IChldmVudDogYW55KSA9PiB7XG4gIFxuICAgIGNvbnN0IG1lc3NhZ2UgPSBldmVudDsgLy8gTWVzc2FnZVBvcnQgZXZlbnRzIGNvbnRhaW4gdGhlIGRhdGEgZGlyZWN0bHlcbiAgICBcbiAgICBpZiAoIW1lc3NhZ2UgfHwgdHlwZW9mIG1lc3NhZ2UgIT09ICdvYmplY3QnKSB7XG4gICAgIFxuICAgICAgcmV0dXJuOyAvLyBJZ25vcmUgaW52YWxpZCBtZXNzYWdlc1xuICAgIH1cbiAgICBcblxuICAgIHN3aXRjaCAobWVzc2FnZS50eXBlKSB7XG4gICAgICBjYXNlIFwiUkVBRFlcIjpcbiAgICAgICAgLy8gRmxvdyBjb250cm9sOiBIVE1MIHdvcmtlciBpcyByZWFkeSBmb3IgbW9yZSBkYXRhXG4gICAgICAgIGlmICh2ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gSFRNTCB3b3JrZXIgcmVhZHkgZm9yIG1vcmUgZGF0YWApO1xuICAgICAgICB9XG4gICAgICAgIC8vIFByb2Nlc3MgYW55IHBlbmRpbmcgUlNDIGNodW5rcyB0aGF0IHdlcmUgYnVmZmVyZWQgZHVlIHRvIGJhY2twcmVzc3VyZVxuICAgICAgICBwcm9jZXNzUGVuZGluZ1JzY0NodW5rcygpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgXCJFTkRcIjpcbiAgICAgICAgLy8gRG9uJ3QgZW5kIHRoZSBzdHJlYW0geWV0IC0gd2FpdCBmb3IgdGhlIG51bGwgZGF0YSBtZXNzYWdlXG4gICAgICAgIC8vIFRoZSB3b3JrZXIgd2lsbCBzZW5kIG51bGwgdGhyb3VnaCB0aGUgZGF0YSBwb3J0IHdoZW4gYWN0dWFsbHkgZG9uZVxuICAgICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgYFtjcmVhdGVIdG1sU3RyZWFtLnNlcnZlcjoke3JvdXRlfV0gUmVjZWl2ZWQgRU5EIG1lc3NhZ2UsIHdhaXRpbmcgZm9yIG51bGwgZGF0YSB0byBjb25maXJtIGNvbXBsZXRpb25gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgXCJFUlJPUlwiOlxuICAgICAgICBjb25zdCBlcnJvciA9IHRvRXJyb3IobWVzc2FnZS5lcnJvciwgbWVzc2FnZS5lcnJvckluZm8pO1xuICAgICAgICBodG1sU3RyZWFtLmRlc3Ryb3koZXJyb3IpO1xuXG4gICAgICAgIC8vIENhbGwgdGhlIGVycm9yIGNhbGxiYWNrIGlmIHByb3ZpZGVkXG4gICAgICAgIGlmIChvbkVycm9yKSB7XG4gICAgICAgICAgY29uc3QgaXNQYW5pYyA9IHBhbmljVGhyZXNob2xkID09PSBcImFsbF9lcnJvcnNcIjtcbiAgICAgICAgICBvbkVycm9yKGVycm9yLCBpc1BhbmljKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENsZWFuIHVwIGxpc3RlbmVycyBhbmQgY2xvc2UgcG9ydHMgd2hlbiBzdHJlYW0gaXMgZGVzdHJveWVkIGR1ZSB0byBlcnJvclxuICAgICAgICBjbGVhbnVwKCk7XG5cbiAgICAgICAgLy8gU2VuZCBjbGVhbnVwIG1lc3NhZ2UgdG8gd29ya2VyIHRvIHJlc2V0IGl0cyBpbnRlcm5hbCBzdGF0ZVxuICAgICAgICAvLyBUaGlzIHByZXZlbnRzIHJhY2UgY29uZGl0aW9ucyBiZXR3ZWVuIHBhZ2UgcmVuZGVyc1xuICAgICAgICBodG1sV29ya2VyLnBvc3RNZXNzYWdlKHsgdHlwZTogXCJDTEVBTlVQXCIsIGlkOiBpZCwgcm91dGU6IHJvdXRlIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgXCJNRVRSSUNTXCI6XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBcIkhUTUxfUkVOREVSX1NUQVJUXCI6XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBcIkNMRUFOVVBfQ09NUExFVEVcIjpcbiAgICAgICAgLy8gV29ya2VyIGhhcyBjb21wbGV0ZWQgY2xlYW51cCAtIHRoaXMgaXMganVzdCBhIGNvbmZpcm1hdGlvblxuICAgICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlci5pbmZvKGBbY3JlYXRlSHRtbFN0cmVhbS5zZXJ2ZXI6JHtyb3V0ZX1dIFdvcmtlciBjbGVhbnVwIGNvbXBsZXRlZCBmb3Igcm91dGUgJHttZXNzYWdlLmlkfWApO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9O1xuICBcbiAgY29udHJvbFBvcnQxLm9uKCdtZXNzYWdlJywgY29udHJvbE1lc3NhZ2VIYW5kbGVyKTtcblxuICAvLyBTZW5kIHRoZSBIVE1MIHN0cmVhbSByZXF1ZXN0IHRvIHRoZSB3b3JrZXIgd2l0aCBib3RoIE1lc3NhZ2VQb3J0c1xuICBodG1sV29ya2VyLnBvc3RNZXNzYWdlKFxuICAgIHtcbiAgICAgIHR5cGU6IFwiSU5JVFwiLFxuICAgICAgaWQ6IHJvdXRlLFxuICAgICAgZGF0YVBvcnQ6IGRhdGFQb3J0MixcbiAgICAgIGNvbnRyb2xQb3J0OiBjb250cm9sUG9ydDIsXG4gICAgICBvcHRpb25zOiBjcmVhdGVTZXJpYWxpemFibGVIYW5kbGVyT3B0aW9ucyhvcHRpb25zKSxcbiAgICB9LFxuICAgIFtkYXRhUG9ydDIsIGNvbnRyb2xQb3J0Ml0gYXMgYW55XG4gICk7IC8vIFRyYW5zZmVyIGJvdGggcG9ydHMgdG8gdGhlIHdvcmtlclxuXG4gIC8vIElmIHdlIGhhdmUgYW4gUlNDIHN0cmVhbSwgcGlwZSBpdCB0byB0aGUgd29ya2VyIHZpYSBkYXRhUG9ydFxuICBpZiAocnNjU3RyZWFtKSB7XG4gICAgaWYgKHZlcmJvc2UpIHtcbiAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICBgW2NyZWF0ZUh0bWxTdHJlYW0uc2VydmVyOiR7cm91dGV9XSBQaXBpbmcgUlNDIHN0cmVhbSB0byBIVE1MIHdvcmtlcmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUGlwZSB0aGUgUlNDIHN0cmVhbSBkYXRhIGRpcmVjdGx5IHRvIHRoZSB3b3JrZXIgdmlhIGRhdGFQb3J0XG4gICAgcnNjU3RyZWFtLm9uKFwiZGF0YVwiLCAoY2h1bmspID0+IHtcbiAgICAgIHNlbmRDaHVuayhjaHVuayk7XG4gICAgfSk7XG5cbiAgICByc2NTdHJlYW0ub24oXCJlbmRcIiwgKCkgPT4ge1xuICAgICAgaXNTdHJlYW1FbmRlZCA9IHRydWU7XG4gICAgfSk7XG5cbiAgICByc2NTdHJlYW0ub24oXCJlcnJvclwiLCAoZXJyb3IpID0+IHtcbiAgICAgIGNvbnN0IHNlcmlhbGl6ZWRFcnJvciA9IHNlcmlhbGl6ZUVycm9yKGVycm9yKTtcbiAgICAgIGNvbnRyb2xQb3J0MS5wb3N0TWVzc2FnZSh7IHR5cGU6IFwiRVJST1JcIiwgZXJyb3I6IHNlcmlhbGl6ZWRFcnJvciB9KTtcbiAgICAgIGRhdGFQb3J0MS5wb3N0TWVzc2FnZSh7IGVycm9yOiBzZXJpYWxpemVkRXJyb3IgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBVbmlmaWVkIGNsZWFudXAgZnVuY3Rpb24gdGhhdCBoYW5kbGVzIGxpc3RlbmVycyBvbmx5XG4gIC8vIExldCBSZWFjdCBtYW5hZ2UgdGhlIE1lc3NhZ2VQb3J0IGxpZmVjeWNsZSB0byBwcmV2ZW50IFwiQ29ubmVjdGlvbiBjbG9zZWRcIiBlcnJvcnNcbiAgY29uc3QgY2xlYW51cCA9ICgpID0+IHtcbiAgICB0cnkge1xuICAgICAgZGF0YVBvcnQxLnJlbW92ZUxpc3RlbmVyKCdtZXNzYWdlJywgZGF0YU1lc3NhZ2VIYW5kbGVyKTtcbiAgICAgIGNvbnRyb2xQb3J0MS5yZW1vdmVMaXN0ZW5lcignbWVzc2FnZScsIGNvbnRyb2xNZXNzYWdlSGFuZGxlcik7XG4gICAgICAvLyBEb24ndCBjbG9zZSBwb3J0cyAtIGxldCBSZWFjdCBmaW5pc2ggY29uc3VtaW5nIGFuZCBjbG9zZSBuYXR1cmFsbHlcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gSWdub3JlIGNsZWFudXAgZXJyb3JzXG4gICAgfVxuICB9O1xuXG4gIC8vIE5vdGU6IFByb2Nlc3MtbGV2ZWwgY2xlYW51cCBpcyBoYW5kbGVkIGJ5IHdvcmtlciBzaHV0ZG93biBwcm90b2NvbFxuXG4gIHJldHVybiB7XG4gICAgcGlwZTogKGRlc3RpbmF0aW9uOiBhbnkpID0+IGh0bWxTdHJlYW0ucGlwZShkZXN0aW5hdGlvbiksXG4gICAgICBhYm9ydDogKCkgPT4ge1xuICAgIGNvbnRyb2xQb3J0MS5wb3N0TWVzc2FnZSh7IHR5cGU6IFwiQUJPUlRcIiwgcmVhc29uOiBcIlN0cmVhbSBhYm9ydGVkXCIgfSk7XG4gICAgaHRtbFN0cmVhbS5lbmQoKTtcblxuICAgIC8vIFVzZSB1bmlmaWVkIGNsZWFudXBcbiAgICBjbGVhbnVwKCk7XG5cbiAgICAvLyBTZW5kIGNsZWFudXAgbWVzc2FnZSB0byB3b3JrZXIgdG8gcmVzZXQgaXRzIGludGVybmFsIHN0YXRlXG4gICAgLy8gVGhpcyBwcmV2ZW50cyByYWNlIGNvbmRpdGlvbnMgYmV0d2VlbiBwYWdlIHJlbmRlcnNcbiAgICBodG1sV29ya2VyLnBvc3RNZXNzYWdlKHsgdHlwZTogXCJDTEVBTlVQXCIsIGlkOiBpZCwgcm91dGU6IHJvdXRlIH0pO1xuICB9LFxuICB9O1xufTtcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFVYSxNQUFBLGdCQUFBLEdBQXVDLFNBQVMsaUJBQUEsQ0FDM0QsT0FDQSxFQUFBO0FBQ0EsRUFBTSxNQUFBO0FBQUEsSUFDSixLQUFBO0FBQUEsSUFDQSxFQUFLLEdBQUEsS0FBQTtBQUFBLElBQ0wsU0FBQTtBQUFBLElBQ0EsVUFB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