vite-plugin-react-server 1.4.2 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -313
- package/dist/package.json +123 -13
- package/dist/plugin/bundle/deferredStaticGeneration.js +14 -39
- package/dist/plugin/bundle/manifests.js +30 -48
- package/dist/plugin/config/autoDiscover/resolveAutoDiscover.d.ts.map +1 -1
- package/dist/plugin/config/autoDiscover/resolveAutoDiscover.js +4 -1
- package/dist/plugin/config/envPrefixFromConfig.js +12 -7
- package/dist/plugin/config/getCondition.d.ts.map +1 -1
- package/dist/plugin/config/getCondition.js +7 -5
- package/dist/plugin/dev-server/virtualRscHmrPlugin.js +23 -23
- package/dist/plugin/environments/createBuildEventPlugin.js +88 -98
- package/dist/plugin/environments/createEnvironmentPlugin.js +222 -250
- package/dist/plugin/helpers/createRscRenderHelpers.js +33 -34
- package/dist/plugin/helpers/createSharedLoader.d.ts.map +1 -1
- package/dist/plugin/helpers/createSharedLoader.js +4 -2
- package/dist/plugin/helpers/headlessStreamReuseHandler.js +30 -22
- package/dist/plugin/helpers/headlessStreamState.js +15 -28
- package/dist/plugin/helpers/resolveComponent.d.ts.map +1 -1
- package/dist/plugin/helpers/resolveComponent.js +4 -2
- package/dist/plugin/index.client.d.ts +5 -0
- package/dist/plugin/index.client.d.ts.map +1 -0
- package/dist/plugin/index.client.js +4 -0
- package/dist/plugin/index.d.ts +4 -3
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +10 -5
- package/dist/plugin/index.server.d.ts +5 -0
- package/dist/plugin/index.server.d.ts.map +1 -0
- package/dist/plugin/index.server.js +4 -0
- package/dist/plugin/metrics/createWorkerStartupMetrics.js +31 -13
- package/dist/plugin/orchestrator/createPluginOrchestrator.client.js +41 -38
- package/dist/plugin/orchestrator/createPluginOrchestrator.server.js +43 -46
- package/dist/plugin/plugin.client.js +2 -2
- package/dist/plugin/plugin.server.js +2 -2
- package/dist/plugin/react-static/createBuildLoader.client.js +12 -6
- package/dist/plugin/react-static/createBuildLoader.server.js +255 -235
- package/dist/plugin/react-static/plugin.client.js +684 -770
- package/dist/plugin/react-static/plugin.server.js +517 -603
- package/dist/plugin/react-static/processCssFilesForPages.js +103 -88
- package/dist/plugin/react-static/renderPage.client.js +455 -529
- package/dist/plugin/react-static/renderPage.server.js +485 -508
- package/dist/plugin/react-static/renderPagesBatched.js +277 -275
- package/dist/plugin/react-static/rscToHtmlStream.client.js +48 -29
- package/dist/plugin/react-static/rscToHtmlStream.server.js +62 -37
- package/dist/plugin/react-static/temporaryReferences.server.js +11 -2
- package/dist/plugin/stream/createMainThreadHandlers.js +40 -31
- package/dist/plugin/stream/renderRscStream.server.d.ts.map +1 -1
- package/dist/plugin/stream/renderRscStream.server.js +127 -144
- package/dist/plugin/transformer/createTransformerPlugin.js +226 -265
- package/dist/plugin/utils/checkReactVersion.d.ts +7 -0
- package/dist/plugin/utils/checkReactVersion.d.ts.map +1 -0
- package/dist/plugin/utils/checkReactVersion.js +23 -0
- package/dist/plugin/utils/envUrls.node.js +12 -11
- package/dist/plugin/vendor/vendor-alias.js +84 -114
- package/dist/plugin/vendor/vendor.client.d.ts.map +1 -1
- package/dist/plugin/vendor/vendor.client.js +1 -3
- package/dist/plugin/worker/rsc/handleRscRender.d.ts.map +1 -1
- package/dist/plugin/worker/rsc/handleRscRender.js +3 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +123 -13
- package/plugin/config/autoDiscover/resolveAutoDiscover.ts +4 -0
- package/plugin/config/getCondition.ts +6 -4
- package/plugin/helpers/createRscRenderHelpers.ts +1 -1
- package/plugin/helpers/createSharedLoader.ts +6 -1
- package/plugin/helpers/resolveComponent.ts +6 -1
- package/plugin/index.client.ts +4 -0
- package/plugin/index.server.ts +4 -0
- package/plugin/index.ts +12 -5
- package/plugin/plugin.client.ts +1 -1
- package/plugin/plugin.server.ts +1 -1
- package/plugin/stream/renderRscStream.server.ts +3 -0
- package/plugin/utils/checkReactVersion.ts +28 -0
- package/plugin/vendor/vendor.client.ts +0 -2
- package/plugin/worker/rsc/handleRscRender.ts +2 -0
- package/scripts/generate-toc.mjs +27 -294
|
@@ -1,623 +1,537 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* plugin
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* This module:
|
|
7
|
-
* 1. Orchestrates the entire static site generation process
|
|
8
|
-
* 2. Manages the lifecycle of the RSC rendering process
|
|
9
|
-
* 3. Handles file writing for both initial page loads and client-side navigation
|
|
10
|
-
* - Writes .html files for initial page loads (complete HTML document)
|
|
11
|
-
* - Writes .rsc files for client-side navigation (RSC content only)
|
|
12
|
-
* 4. Provides hooks for Vite to integrate with the build process
|
|
13
|
-
* 5. Manages worker threads for parallel rendering
|
|
14
|
-
* 6. Handles error reporting and metrics collection
|
|
2
|
+
* vite-plugin-react-server
|
|
3
|
+
* Copyright (c) Nico Brinkkemper
|
|
4
|
+
* MIT License
|
|
15
5
|
*/
|
|
16
|
-
import { createLogger
|
|
17
|
-
import { resolveOptions } from
|
|
18
|
-
import { createBuildLoader } from
|
|
19
|
-
import { renderPagesBatched } from
|
|
20
|
-
import { renderPages
|
|
21
|
-
import { getBundleManifest } from
|
|
22
|
-
import { createWorker } from
|
|
23
|
-
import { serializedOptions, serializeResolvedConfig
|
|
24
|
-
import { performance } from
|
|
25
|
-
import { baseURL } from
|
|
26
|
-
import { handleError } from
|
|
27
|
-
import { shouldCausePanic } from
|
|
28
|
-
import { renderPage } from
|
|
29
|
-
import { temporaryReferences } from
|
|
30
|
-
import { configurePreviewServer } from
|
|
31
|
-
import { envPrefixFromConfig } from
|
|
32
|
-
import { processCssFilesForPages } from
|
|
33
|
-
import { createWorkerStartupMetrics } from
|
|
34
|
-
import { tryManifest } from
|
|
35
|
-
import { join } from
|
|
36
|
-
import { resolveAutoDiscover } from
|
|
37
|
-
import { assertReactServer } from
|
|
38
|
-
import { toError } from
|
|
6
|
+
import { createLogger } from 'vite';
|
|
7
|
+
import { resolveOptions } from '../config/resolveOptions.js';
|
|
8
|
+
import { createBuildLoader } from './createBuildLoader.server.js';
|
|
9
|
+
import { renderPagesBatched } from './renderPagesBatched.js';
|
|
10
|
+
import { renderPages } from './renderPages.js';
|
|
11
|
+
import { getBundleManifest } from '../helpers/getBundleManifest.js';
|
|
12
|
+
import { createWorker } from '../worker/createWorker.js';
|
|
13
|
+
import { serializedOptions, serializeResolvedConfig } from '../helpers/serializeUserOptions.js';
|
|
14
|
+
import { performance } from 'node:perf_hooks';
|
|
15
|
+
import { baseURL } from '../utils/envUrls.node.js';
|
|
16
|
+
import { handleError } from '../error/handleError.js';
|
|
17
|
+
import { shouldCausePanic } from '../error/panicThresholdHandler.js';
|
|
18
|
+
import { renderPage } from './renderPage.server.js';
|
|
19
|
+
import { temporaryReferences } from './temporaryReferences.server.js';
|
|
20
|
+
import { configurePreviewServer } from './configurePreviewServer.js';
|
|
21
|
+
import { envPrefixFromConfig } from '../config/envPrefixFromConfig.js';
|
|
22
|
+
import { processCssFilesForPages } from './processCssFilesForPages.js';
|
|
23
|
+
import { createWorkerStartupMetrics } from '../metrics/createWorkerStartupMetrics.js';
|
|
24
|
+
import { tryManifest } from '../helpers/tryManifest.js';
|
|
25
|
+
import { join } from 'node:path';
|
|
26
|
+
import { resolveAutoDiscover } from '../config/autoDiscover/resolveAutoDiscover.js';
|
|
27
|
+
import { assertReactServer } from '../config/getCondition.js';
|
|
28
|
+
import { toError } from '../error/toError.js';
|
|
29
|
+
|
|
39
30
|
assertReactServer();
|
|
40
|
-
/**
|
|
41
|
-
* Main entrypoint for the static plugin.
|
|
42
|
-
*
|
|
43
|
-
* This plugin is responsible for:
|
|
44
|
-
* 1. Orchestrating the static site generation process
|
|
45
|
-
* 2. Handling the lifecycle of the RSC rendering process (main thread)
|
|
46
|
-
* 3. Writing .html files for initial page loads (complete HTML document)
|
|
47
|
-
* 4. Writing .rsc files for client-side navigation (RSC content only)
|
|
48
|
-
* 5. Managing worker threads for parallel rendering (html worker)
|
|
49
|
-
* 6. Handling error reporting and metrics collection
|
|
50
|
-
*/
|
|
51
|
-
// Global worker instance to prevent duplicate creation across plugin instances
|
|
52
31
|
let globalWorker;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
32
|
+
const reactStaticPlugin = function _reactStaticPlugin(options) {
|
|
33
|
+
let worker;
|
|
34
|
+
let logger;
|
|
35
|
+
let resolvedConfig;
|
|
36
|
+
let autoDiscoveredFiles = null;
|
|
37
|
+
let serverManifest = void 0;
|
|
38
|
+
let configEnv;
|
|
39
|
+
const timing = {
|
|
40
|
+
start: performance.now(),
|
|
41
|
+
configResolved: 0,
|
|
42
|
+
buildStart: 0,
|
|
43
|
+
renderStart: 0
|
|
44
|
+
};
|
|
45
|
+
const resolvedOptions = resolveOptions(options);
|
|
46
|
+
if (resolvedOptions.type === "error") {
|
|
47
|
+
throw resolvedOptions.error;
|
|
48
|
+
}
|
|
49
|
+
const userOptions = resolvedOptions.userOptions;
|
|
50
|
+
return {
|
|
51
|
+
name: "vite:plugin-react-server/server-static",
|
|
52
|
+
enforce: "post",
|
|
53
|
+
api: {
|
|
54
|
+
meta: { timing }
|
|
55
|
+
},
|
|
56
|
+
async config(_config, viteConfigEnv) {
|
|
57
|
+
configEnv = viteConfigEnv;
|
|
58
|
+
},
|
|
59
|
+
applyToEnvironment(partialEnvironment) {
|
|
60
|
+
if (["server"].includes(
|
|
61
|
+
partialEnvironment.name
|
|
62
|
+
)) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
},
|
|
67
|
+
async configResolved(config) {
|
|
68
|
+
resolvedConfig = config;
|
|
69
|
+
if (!logger) {
|
|
70
|
+
logger = config.customLogger ?? createLogger();
|
|
71
|
+
}
|
|
72
|
+
const autoDiscoverResult = await resolveAutoDiscover({
|
|
73
|
+
config,
|
|
74
|
+
configEnv,
|
|
75
|
+
userOptions,
|
|
76
|
+
logger
|
|
77
|
+
});
|
|
78
|
+
if (autoDiscoverResult.type === "error") {
|
|
79
|
+
throw autoDiscoverResult.error;
|
|
80
|
+
}
|
|
81
|
+
autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
|
|
82
|
+
},
|
|
83
|
+
async buildStart() {
|
|
84
|
+
if (!logger) {
|
|
85
|
+
logger = this.environment.logger;
|
|
86
|
+
}
|
|
87
|
+
timing.buildStart = performance.now();
|
|
88
|
+
if (userOptions.onEvent && autoDiscoveredFiles) {
|
|
89
|
+
try {
|
|
90
|
+
userOptions.onEvent({
|
|
91
|
+
type: "build.start",
|
|
92
|
+
data: {
|
|
93
|
+
pages: Array.from(autoDiscoveredFiles.urlMap.keys()),
|
|
94
|
+
files: autoDiscoveredFiles
|
|
83
95
|
}
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
});
|
|
97
|
+
} catch (error) {
|
|
98
|
+
const panicError = handleError({
|
|
99
|
+
error,
|
|
100
|
+
logger,
|
|
101
|
+
panicThreshold: userOptions.panicThreshold});
|
|
102
|
+
if (panicError != null) {
|
|
103
|
+
worker?.terminate();
|
|
104
|
+
throw panicError;
|
|
105
|
+
} else {
|
|
106
|
+
this.error(new Error("Failed to emit build.start event"));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
// the preview server helps to view the generated static folder, but only when the static plugin is enabled
|
|
112
|
+
// if no build.pages, then the preview server will instead use default vite preview server
|
|
113
|
+
// it works the same under both conditions
|
|
114
|
+
async configurePreviewServer(server) {
|
|
115
|
+
logger = server.config.customLogger || server.config.logger;
|
|
116
|
+
configurePreviewServer({
|
|
117
|
+
server,
|
|
118
|
+
userOptions
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
async renderStart() {
|
|
122
|
+
timing.renderStart = performance.now();
|
|
123
|
+
},
|
|
124
|
+
generateBundle(_options, bundle) {
|
|
125
|
+
if (this.environment.name === "server") {
|
|
126
|
+
const keysToDelete = [];
|
|
127
|
+
for (const [key, chunk] of Object.entries(bundle)) {
|
|
128
|
+
if (chunk.type === "chunk") {
|
|
129
|
+
const isVirtual = chunk.fileName?.includes("_virtual") || key.includes("_virtual") || chunk.facadeModuleId?.includes("_virtual") || chunk.moduleIds?.some((id) => id.includes("_virtual"));
|
|
130
|
+
const isDynamicImportHelper = chunk.fileName?.includes("dynamic-import-helper") || key.includes("dynamic-import-helper");
|
|
131
|
+
if (isVirtual && !isDynamicImportHelper) {
|
|
132
|
+
keysToDelete.push(key);
|
|
133
|
+
if (userOptions.verbose) {
|
|
134
|
+
logger?.info(`[plugin.server] Filtered out virtual file: ${chunk.fileName || key} (moduleId: ${chunk.facadeModuleId || chunk.moduleIds?.[0]})`);
|
|
135
|
+
}
|
|
90
136
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
for (const key of keysToDelete) {
|
|
140
|
+
delete bundle[key];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
async writeBundle(_options, bundle) {
|
|
145
|
+
if (this.environment.name !== "server") {
|
|
146
|
+
if (userOptions.verbose) {
|
|
147
|
+
logger?.info(`[plugin.server] Skipping static generation for environment: ${this.environment.name}`);
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
let panicError = null;
|
|
152
|
+
let bundleManifest = void 0;
|
|
153
|
+
if (!logger) {
|
|
154
|
+
logger = this.environment.logger;
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
bundleManifest = getBundleManifest({
|
|
158
|
+
bundle,
|
|
159
|
+
normalizer: userOptions.normalizer
|
|
160
|
+
});
|
|
161
|
+
const manifestPath = typeof resolvedConfig.build.manifest === "string" ? resolvedConfig.build.manifest : ".vite/manifest.json";
|
|
162
|
+
if (!bundleManifest[manifestPath] || !("source" in bundleManifest[manifestPath])) {
|
|
163
|
+
throw new Error("Server manifest not found");
|
|
164
|
+
}
|
|
165
|
+
serverManifest = JSON.parse(
|
|
166
|
+
bundleManifest[manifestPath].source
|
|
167
|
+
);
|
|
168
|
+
if (!serverManifest) {
|
|
169
|
+
throw new Error("Failed to parse server manifest");
|
|
170
|
+
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
const panicError2 = handleError({
|
|
173
|
+
error,
|
|
174
|
+
logger,
|
|
175
|
+
panicThreshold: userOptions.panicThreshold});
|
|
176
|
+
if (panicError2 != null) {
|
|
177
|
+
throw panicError2;
|
|
178
|
+
} else {
|
|
179
|
+
throw new Error("Failed to get bundle manifest");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const staticManifestResult = await tryManifest({
|
|
184
|
+
root: userOptions.projectRoot,
|
|
185
|
+
outDir: join(userOptions.build.outDir, userOptions.build.static),
|
|
186
|
+
manifestPath: resolvedConfig.build.manifest,
|
|
187
|
+
ssrManifest: false
|
|
188
|
+
});
|
|
189
|
+
if (staticManifestResult.type === "error") {
|
|
190
|
+
throw staticManifestResult.error;
|
|
191
|
+
}
|
|
192
|
+
const staticManifest = staticManifestResult.manifest;
|
|
193
|
+
const buildLoader = createBuildLoader(
|
|
194
|
+
{
|
|
195
|
+
userOptions,
|
|
196
|
+
serverManifest: serverManifest ?? {},
|
|
197
|
+
staticManifest
|
|
198
|
+
},
|
|
199
|
+
bundle,
|
|
200
|
+
temporaryReferences,
|
|
201
|
+
logger
|
|
202
|
+
);
|
|
203
|
+
const { cssFilesByPage, globalCss } = processCssFilesForPages({
|
|
204
|
+
userOptions,
|
|
205
|
+
autoDiscoveredFiles,
|
|
206
|
+
serverManifest,
|
|
207
|
+
staticManifest,
|
|
208
|
+
bundle,
|
|
209
|
+
logger
|
|
210
|
+
});
|
|
211
|
+
if (userOptions.verbose) {
|
|
212
|
+
logger.info(
|
|
213
|
+
`[plugin.server] cssFilesByPage size: ${cssFilesByPage.size}`
|
|
214
|
+
);
|
|
215
|
+
for (const [route, cssMap] of cssFilesByPage.entries()) {
|
|
216
|
+
logger.info(
|
|
217
|
+
`[plugin.server] Route ${route}: ${cssMap.size} CSS files`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const indexHtml = staticManifest?.["index.html"]?.file;
|
|
222
|
+
const serverPipeableStreamOptions = {
|
|
223
|
+
...userOptions.serverPipeableStreamOptions,
|
|
224
|
+
bootstrapModules: [
|
|
225
|
+
...indexHtml ? [baseURL(indexHtml)] : [],
|
|
226
|
+
...userOptions.serverPipeableStreamOptions?.bootstrapModules ?? []
|
|
227
|
+
]
|
|
228
|
+
};
|
|
229
|
+
userOptions.serverPipeableStreamOptions = serverPipeableStreamOptions;
|
|
230
|
+
const clientPipeableStreamOptions = {
|
|
231
|
+
...userOptions.clientPipeableStreamOptions,
|
|
232
|
+
bootstrapModules: [
|
|
233
|
+
...indexHtml ? [baseURL(indexHtml)] : [],
|
|
234
|
+
...userOptions.clientPipeableStreamOptions?.bootstrapModules ?? []
|
|
235
|
+
]
|
|
236
|
+
};
|
|
237
|
+
const routes = !autoDiscoveredFiles ? [] : Array.from(autoDiscoveredFiles.urlMap.keys());
|
|
238
|
+
if (routes.length === 0) {
|
|
239
|
+
logger?.info(
|
|
240
|
+
"[plugin.server] No pages to generate, skipping static generation"
|
|
241
|
+
);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const serializedUserOptions = serializedOptions(
|
|
245
|
+
userOptions,
|
|
246
|
+
autoDiscoveredFiles
|
|
247
|
+
);
|
|
248
|
+
if (globalWorker) {
|
|
249
|
+
logger?.warn("[plugin.server] Global worker already exists, reusing existing worker");
|
|
250
|
+
worker = globalWorker;
|
|
251
|
+
} else {
|
|
252
|
+
const workerStartTime = performance.now();
|
|
253
|
+
const viteEnvPrefix = envPrefixFromConfig(resolvedConfig);
|
|
254
|
+
const routeCount = autoDiscoveredFiles?.urlMap.size ?? 0;
|
|
255
|
+
const maxListeners = routeCount + 1;
|
|
256
|
+
const workerResult = await createWorker({
|
|
257
|
+
projectRoot: userOptions.projectRoot,
|
|
258
|
+
workerPath: userOptions.htmlWorkerPath,
|
|
259
|
+
currentCondition: "react-server",
|
|
260
|
+
reverseCondition: "react-client",
|
|
261
|
+
// HTML worker needs react-client for react-dom/server
|
|
262
|
+
maxListeners,
|
|
263
|
+
envPrefix: viteEnvPrefix,
|
|
264
|
+
logger,
|
|
265
|
+
workerData: {
|
|
266
|
+
resolvedConfig: serializeResolvedConfig(resolvedConfig),
|
|
267
|
+
userOptions: serializedUserOptions,
|
|
268
|
+
configEnv
|
|
99
269
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
logger = this.environment.logger;
|
|
270
|
+
});
|
|
271
|
+
if (workerResult.type === "error") {
|
|
272
|
+
if (workerResult.error != null) {
|
|
273
|
+
throw workerResult.error;
|
|
105
274
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
else {
|
|
129
|
-
this.error(new Error("Failed to emit build.start event"));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
275
|
+
throw new Error("React static plugin failed to create worker");
|
|
276
|
+
} else if (workerResult.type === "skip") {
|
|
277
|
+
logger.info("Worker not created, skipping static build");
|
|
278
|
+
return;
|
|
279
|
+
} else {
|
|
280
|
+
worker = workerResult.worker;
|
|
281
|
+
const workerStartupTime = performance.now() - workerStartTime;
|
|
282
|
+
if (userOptions.onMetrics) {
|
|
283
|
+
const workerStartupMetric = createWorkerStartupMetrics({
|
|
284
|
+
route: "/",
|
|
285
|
+
// Worker startup is global, not route-specific
|
|
286
|
+
workerType: "html",
|
|
287
|
+
// This is the HTML worker for server-side static generation
|
|
288
|
+
startupTime: workerStartupTime,
|
|
289
|
+
fromMainThread: true,
|
|
290
|
+
fromRscWorker: false,
|
|
291
|
+
fromHtmlWorker: false,
|
|
292
|
+
description: `HTML worker startup for server-side static generation`
|
|
293
|
+
});
|
|
294
|
+
if (this.environment.name === "server") {
|
|
295
|
+
userOptions.onMetrics(workerStartupMetric);
|
|
296
|
+
}
|
|
132
297
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
298
|
+
globalWorker = worker;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const { onEvent, ...handlerOptions } = userOptions;
|
|
302
|
+
if (typeof userOptions.onEvent === "function") {
|
|
303
|
+
try {
|
|
304
|
+
const r = userOptions.onEvent({
|
|
305
|
+
type: "build.ssg.start",
|
|
306
|
+
data: {
|
|
307
|
+
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
308
|
+
options: null,
|
|
309
|
+
// No specific rollup output options for static generation
|
|
310
|
+
bundle
|
|
311
|
+
}
|
|
142
312
|
});
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
timing.renderStart = performance.now();
|
|
146
|
-
},
|
|
147
|
-
generateBundle(_options, bundle) {
|
|
148
|
-
// Filter out unnecessary _virtual files from the bundle
|
|
149
|
-
// Keep dynamic-import-helper.js since it's needed for dynamic imports
|
|
150
|
-
// Note: Static builds are handled by plugin.client.ts, this only handles server builds
|
|
151
|
-
if (this.environment.name === "server") {
|
|
152
|
-
const keysToDelete = [];
|
|
153
|
-
for (const [key, chunk] of Object.entries(bundle)) {
|
|
154
|
-
if (chunk.type === "chunk") {
|
|
155
|
-
// Check fileName, key, moduleIds, and facadeModuleId for _virtual
|
|
156
|
-
const isVirtual = chunk.fileName?.includes("_virtual") ||
|
|
157
|
-
key.includes("_virtual") ||
|
|
158
|
-
chunk.facadeModuleId?.includes("_virtual") ||
|
|
159
|
-
chunk.moduleIds?.some(id => id.includes("_virtual"));
|
|
160
|
-
// Keep dynamic-import-helper.js - it's needed for dynamic imports
|
|
161
|
-
const isDynamicImportHelper = chunk.fileName?.includes("dynamic-import-helper") ||
|
|
162
|
-
key.includes("dynamic-import-helper");
|
|
163
|
-
if (isVirtual && !isDynamicImportHelper) {
|
|
164
|
-
keysToDelete.push(key);
|
|
165
|
-
if (userOptions.verbose) {
|
|
166
|
-
logger?.info(`[plugin.server] Filtered out virtual file: ${chunk.fileName || key} (moduleId: ${chunk.facadeModuleId || chunk.moduleIds?.[0]})`);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
// Delete after iteration to avoid modifying while iterating
|
|
172
|
-
for (const key of keysToDelete) {
|
|
173
|
-
delete bundle[key];
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
async writeBundle(_options, bundle) {
|
|
178
|
-
// Only execute static generation for the server environment
|
|
179
|
-
if (this.environment.name !== "server") {
|
|
180
|
-
if (userOptions.verbose) {
|
|
181
|
-
logger?.info(`[plugin.server] Skipping static generation for environment: ${this.environment.name}`);
|
|
182
|
-
}
|
|
183
|
-
return;
|
|
313
|
+
if (r != null && typeof r === "object" && "then" in r) {
|
|
314
|
+
await r;
|
|
184
315
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
316
|
+
} catch (error) {
|
|
317
|
+
const eventPanicError = handleError({
|
|
318
|
+
error,
|
|
319
|
+
logger,
|
|
320
|
+
panicThreshold: userOptions.panicThreshold,
|
|
321
|
+
context: "onEvent(build.ssg.start)"
|
|
322
|
+
});
|
|
323
|
+
if (eventPanicError != null) {
|
|
324
|
+
throw eventPanicError;
|
|
325
|
+
} else {
|
|
326
|
+
throw new Error("Failed to emit build.ssg.start event");
|
|
189
327
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const renderMode = userOptions.build?.renderMode ?? "parallel";
|
|
331
|
+
const renderPages$1 = renderMode === "sequential" ? renderPages : renderPagesBatched;
|
|
332
|
+
if (userOptions.verbose) {
|
|
333
|
+
logger.info(`[static] Using ${renderMode} rendering${renderMode === "parallel" ? ` (batch size: ${userOptions.build?.batchSize ?? 8})` : ""}`);
|
|
334
|
+
}
|
|
335
|
+
const renderPagesGenerator = renderPages$1(
|
|
336
|
+
routes,
|
|
337
|
+
{
|
|
338
|
+
...handlerOptions,
|
|
339
|
+
loader: buildLoader,
|
|
340
|
+
worker,
|
|
341
|
+
htmlWorker: worker,
|
|
342
|
+
// Pass the HTML worker for HTML generation
|
|
343
|
+
logger,
|
|
344
|
+
// Pass global CSS to downstream renderer
|
|
345
|
+
globalCss,
|
|
346
|
+
// Pass abort signal to cancel operations when errors occur
|
|
347
|
+
signal: AbortSignal.timeout(handlerOptions.htmlTimeout),
|
|
348
|
+
onEvent,
|
|
349
|
+
serverPipeableStreamOptions,
|
|
350
|
+
clientPipeableStreamOptions,
|
|
351
|
+
manifest: serverManifest ?? {},
|
|
352
|
+
staticManifest,
|
|
353
|
+
// Pass static manifest for path resolution
|
|
354
|
+
autoDiscoveredFiles,
|
|
355
|
+
cssFilesByPage,
|
|
356
|
+
batchSize: userOptions.build?.batchSize
|
|
357
|
+
},
|
|
358
|
+
renderPage
|
|
359
|
+
);
|
|
360
|
+
let finalResult;
|
|
361
|
+
try {
|
|
362
|
+
for await (const result of renderPagesGenerator) {
|
|
363
|
+
if (result.type === "error") {
|
|
364
|
+
throw result.error;
|
|
210
365
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
throw new Error("Failed to get bundle manifest");
|
|
223
|
-
}
|
|
366
|
+
if (result.type === "success" && result.failedRoutes && result.failedRoutes.size > 0) {
|
|
367
|
+
const firstError = result.failedRoutes.values().next().value;
|
|
368
|
+
if (firstError != null && shouldCausePanic(firstError, { panicThreshold: userOptions.panicThreshold })) {
|
|
369
|
+
throw firstError;
|
|
370
|
+
}
|
|
371
|
+
for (const [route, error] of result.failedRoutes) {
|
|
372
|
+
const err = error instanceof Error ? error : toError(error);
|
|
373
|
+
this.warn(
|
|
374
|
+
new Error("Failed to render route: " + route + "\n" + err.message + "\n" + err.stack, { cause: err })
|
|
375
|
+
);
|
|
376
|
+
}
|
|
224
377
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
bootstrapModules: [
|
|
262
|
-
...(indexHtml ? [baseURL(indexHtml)] : []),
|
|
263
|
-
...(userOptions.serverPipeableStreamOptions?.bootstrapModules ??
|
|
264
|
-
[]),
|
|
265
|
-
],
|
|
266
|
-
};
|
|
267
|
-
userOptions.serverPipeableStreamOptions = serverPipeableStreamOptions;
|
|
268
|
-
const clientPipeableStreamOptions = {
|
|
269
|
-
...userOptions.clientPipeableStreamOptions,
|
|
270
|
-
bootstrapModules: [
|
|
271
|
-
...(indexHtml ? [baseURL(indexHtml)] : []),
|
|
272
|
-
...(userOptions.clientPipeableStreamOptions?.bootstrapModules ??
|
|
273
|
-
[]),
|
|
274
|
-
],
|
|
275
|
-
};
|
|
276
|
-
// Get routes for worker configuration
|
|
277
|
-
const routes = !autoDiscoveredFiles
|
|
278
|
-
? []
|
|
279
|
-
: Array.from(autoDiscoveredFiles.urlMap.keys());
|
|
280
|
-
// If no pages to generate, skip static generation entirely (including worker creation)
|
|
281
|
-
if (routes.length === 0) {
|
|
282
|
-
logger?.info("[plugin.server] No pages to generate, skipping static generation");
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
const serializedUserOptions = serializedOptions(userOptions, autoDiscoveredFiles);
|
|
286
|
-
// Create HTML worker for HTML generation
|
|
287
|
-
// IMPORTANT: We create a new worker for each page render to ensure completely clean state
|
|
288
|
-
// This prevents race conditions where worker state persists between renders
|
|
289
|
-
// Guard against duplicate worker creation if plugin is instantiated multiple times
|
|
290
|
-
if (globalWorker) {
|
|
291
|
-
logger?.warn("[plugin.server] Global worker already exists, reusing existing worker");
|
|
292
|
-
worker = globalWorker;
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
const workerStartTime = performance.now();
|
|
296
|
-
const viteEnvPrefix = envPrefixFromConfig(resolvedConfig);
|
|
297
|
-
const routeCount = autoDiscoveredFiles?.urlMap.size ?? 0;
|
|
298
|
-
const maxListeners = routeCount + 1;
|
|
299
|
-
const workerResult = await createWorker({
|
|
300
|
-
projectRoot: userOptions.projectRoot,
|
|
301
|
-
workerPath: userOptions.htmlWorkerPath,
|
|
302
|
-
currentCondition: "react-server",
|
|
303
|
-
reverseCondition: "react-client", // HTML worker needs react-client for react-dom/server
|
|
304
|
-
maxListeners: maxListeners,
|
|
305
|
-
envPrefix: viteEnvPrefix,
|
|
306
|
-
logger: logger,
|
|
307
|
-
workerData: {
|
|
308
|
-
resolvedConfig: serializeResolvedConfig(resolvedConfig),
|
|
309
|
-
userOptions: serializedUserOptions,
|
|
310
|
-
configEnv,
|
|
311
|
-
},
|
|
312
|
-
});
|
|
313
|
-
if (workerResult.type === "error") {
|
|
314
|
-
if (workerResult.error != null) {
|
|
315
|
-
throw workerResult.error;
|
|
316
|
-
}
|
|
317
|
-
throw new Error("React static plugin failed to create worker");
|
|
318
|
-
}
|
|
319
|
-
else if (workerResult.type === "skip") {
|
|
320
|
-
logger.info("Worker not created, skipping static build");
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
worker = workerResult.worker;
|
|
325
|
-
// Emit worker startup metric after worker is created
|
|
326
|
-
const workerStartupTime = performance.now() - workerStartTime;
|
|
327
|
-
if (userOptions.onMetrics) {
|
|
328
|
-
const workerStartupMetric = createWorkerStartupMetrics({
|
|
329
|
-
route: "/", // Worker startup is global, not route-specific
|
|
330
|
-
workerType: "html", // This is the HTML worker for server-side static generation
|
|
331
|
-
startupTime: workerStartupTime,
|
|
332
|
-
fromMainThread: true,
|
|
333
|
-
fromRscWorker: false,
|
|
334
|
-
fromHtmlWorker: false,
|
|
335
|
-
description: `HTML worker startup for server-side static generation`,
|
|
336
|
-
});
|
|
337
|
-
// Only emit metrics from the server environment to prevent duplicates
|
|
338
|
-
if (this.environment.name === "server") {
|
|
339
|
-
userOptions.onMetrics(workerStartupMetric);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
// Store the worker globally to prevent duplicate creation
|
|
343
|
-
globalWorker = worker;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
// No RSC worker needed for static generation - main thread runs with react-server conditions
|
|
347
|
-
// Render pages - component resolution now happens per-route in renderPage
|
|
348
|
-
const { onEvent, ...handlerOptions } = userOptions;
|
|
349
|
-
// Emit the static site generation start event
|
|
350
|
-
if (typeof userOptions.onEvent === "function") {
|
|
351
|
-
try {
|
|
352
|
-
const r = userOptions.onEvent({
|
|
353
|
-
type: "build.ssg.start",
|
|
354
|
-
data: {
|
|
355
|
-
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
356
|
-
options: null, // No specific rollup output options for static generation
|
|
357
|
-
bundle: bundle,
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
if (r != null && typeof r === "object" && "then" in r) {
|
|
361
|
-
await r;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
catch (error) {
|
|
365
|
-
const eventPanicError = handleError({
|
|
366
|
-
error,
|
|
367
|
-
logger: logger,
|
|
368
|
-
panicThreshold: userOptions.panicThreshold,
|
|
369
|
-
context: "onEvent(build.ssg.start)",
|
|
370
|
-
});
|
|
371
|
-
if (eventPanicError != null) {
|
|
372
|
-
throw eventPanicError; // Re-throw to abort the build
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
throw new Error("Failed to emit build.ssg.start event");
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
// Select render mode based on build config
|
|
380
|
-
const renderMode = userOptions.build?.renderMode ?? "parallel";
|
|
381
|
-
const renderPages = renderMode === "sequential" ? renderPagesSequential : renderPagesBatched;
|
|
382
|
-
if (userOptions.verbose) {
|
|
383
|
-
logger.info(`[static] Using ${renderMode} rendering${renderMode === "parallel" ? ` (batch size: ${userOptions.build?.batchSize ?? 8})` : ""}`);
|
|
384
|
-
}
|
|
385
|
-
// this will render the routes
|
|
386
|
-
const renderPagesGenerator = renderPages(routes, {
|
|
387
|
-
...handlerOptions,
|
|
388
|
-
loader: buildLoader,
|
|
389
|
-
worker: worker,
|
|
390
|
-
htmlWorker: worker, // Pass the HTML worker for HTML generation
|
|
391
|
-
logger: logger,
|
|
392
|
-
// Pass global CSS to downstream renderer
|
|
393
|
-
globalCss,
|
|
394
|
-
// Pass abort signal to cancel operations when errors occur
|
|
395
|
-
signal: AbortSignal.timeout(handlerOptions.htmlTimeout),
|
|
396
|
-
onEvent: onEvent,
|
|
397
|
-
serverPipeableStreamOptions: serverPipeableStreamOptions,
|
|
398
|
-
clientPipeableStreamOptions: clientPipeableStreamOptions,
|
|
399
|
-
manifest: serverManifest ?? {},
|
|
400
|
-
staticManifest: staticManifest, // Pass static manifest for path resolution
|
|
401
|
-
autoDiscoveredFiles: autoDiscoveredFiles,
|
|
402
|
-
cssFilesByPage: cssFilesByPage,
|
|
403
|
-
batchSize: userOptions.build?.batchSize,
|
|
404
|
-
}, renderPage);
|
|
405
|
-
// Process render results
|
|
406
|
-
let finalResult;
|
|
407
|
-
try {
|
|
408
|
-
for await (const result of renderPagesGenerator) {
|
|
409
|
-
// Handle error results immediately
|
|
410
|
-
if (result.type === "error") {
|
|
411
|
-
throw result.error;
|
|
412
|
-
}
|
|
413
|
-
// Handle failed routes based on panic threshold
|
|
414
|
-
if (result.type === "success" &&
|
|
415
|
-
result.failedRoutes &&
|
|
416
|
-
result.failedRoutes.size > 0) {
|
|
417
|
-
// Use centralized panic threshold logic
|
|
418
|
-
const firstError = result.failedRoutes.values().next().value;
|
|
419
|
-
if (firstError != null && shouldCausePanic(firstError, { panicThreshold: userOptions.panicThreshold })) {
|
|
420
|
-
// This should cause a panic, throw the error
|
|
421
|
-
throw firstError;
|
|
422
|
-
}
|
|
423
|
-
// For non-panic errors, log warnings but continue
|
|
424
|
-
for (const [route, error] of result.failedRoutes) {
|
|
425
|
-
const err = error instanceof Error ? error : toError(error);
|
|
426
|
-
this.warn(new Error("Failed to render route: " + route + "\n" + err.message + "\n" + err.stack, { cause: err }));
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
finalResult = result;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
catch (renderError) {
|
|
433
|
-
// Handle render errors with panic threshold logic
|
|
434
|
-
const renderPanicError = handleError({
|
|
435
|
-
error: renderError,
|
|
436
|
-
logger: logger,
|
|
437
|
-
panicThreshold: userOptions.panicThreshold,
|
|
438
|
-
context: "renderPages",
|
|
439
|
-
});
|
|
440
|
-
if (renderPanicError != null) {
|
|
441
|
-
throw renderPanicError;
|
|
442
|
-
}
|
|
443
|
-
throw renderError;
|
|
444
|
-
}
|
|
445
|
-
if (!finalResult) {
|
|
446
|
-
throw new Error("No render result produced");
|
|
447
|
-
}
|
|
448
|
-
// Calculate duration from timing
|
|
449
|
-
const duration = Math.round(performance.now() - (timing.renderStart || timing.start));
|
|
450
|
-
this.info(`Rendered ${finalResult.completedRoutes.size} pages in ${duration}ms`);
|
|
451
|
-
// Emit the static site generation completion event once
|
|
452
|
-
if (typeof userOptions.onEvent === "function") {
|
|
453
|
-
try {
|
|
454
|
-
const r = userOptions.onEvent({
|
|
455
|
-
type: "build.ssg.end",
|
|
456
|
-
data: {
|
|
457
|
-
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
458
|
-
options: null, // No specific rollup output options for static generation
|
|
459
|
-
bundle: bundle,
|
|
460
|
-
},
|
|
461
|
-
});
|
|
462
|
-
if (r != null && typeof r === "object" && "then" in r) {
|
|
463
|
-
await r;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
catch (error) {
|
|
467
|
-
if (error != null) {
|
|
468
|
-
throw error; // Re-throw to abort the build
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
throw new Error("Failed to emit build.ssg.end event");
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
if (process.env["NODE_ENV"] !== "production") {
|
|
476
|
-
this.warn(`THIS BUILD IS NOT INTENDED FOR PRODUCTION (${process.env["NODE_ENV"]})`);
|
|
477
|
-
}
|
|
478
|
-
// Update timing
|
|
479
|
-
timing.render =
|
|
480
|
-
performance.now() - (timing.renderStart ?? timing.start);
|
|
481
|
-
}
|
|
482
|
-
catch (error) {
|
|
483
|
-
panicError = handleError({
|
|
484
|
-
error,
|
|
485
|
-
logger: logger,
|
|
486
|
-
panicThreshold: userOptions.panicThreshold,
|
|
487
|
-
context: "writeBundle",
|
|
488
|
-
});
|
|
489
|
-
// Let the finally block handle additional cleanup
|
|
490
|
-
}
|
|
491
|
-
finally {
|
|
492
|
-
// Reset any cached state to prevent issues in subsequent builds
|
|
493
|
-
autoDiscoveredFiles = null;
|
|
494
|
-
serverManifest = undefined;
|
|
495
|
-
// Clean up worker if it exists
|
|
496
|
-
if (worker) {
|
|
497
|
-
try {
|
|
498
|
-
worker.removeAllListeners();
|
|
499
|
-
worker.terminate();
|
|
500
|
-
}
|
|
501
|
-
catch (terminateError) {
|
|
502
|
-
// Ignore termination errors
|
|
503
|
-
}
|
|
504
|
-
worker = undefined;
|
|
505
|
-
// Reset global worker since it's been terminated
|
|
506
|
-
globalWorker = undefined;
|
|
507
|
-
}
|
|
378
|
+
finalResult = result;
|
|
379
|
+
}
|
|
380
|
+
} catch (renderError) {
|
|
381
|
+
const renderPanicError = handleError({
|
|
382
|
+
error: renderError,
|
|
383
|
+
logger,
|
|
384
|
+
panicThreshold: userOptions.panicThreshold,
|
|
385
|
+
context: "renderPages"
|
|
386
|
+
});
|
|
387
|
+
if (renderPanicError != null) {
|
|
388
|
+
throw renderPanicError;
|
|
389
|
+
}
|
|
390
|
+
throw renderError;
|
|
391
|
+
}
|
|
392
|
+
if (!finalResult) {
|
|
393
|
+
throw new Error("No render result produced");
|
|
394
|
+
}
|
|
395
|
+
const duration = Math.round(
|
|
396
|
+
performance.now() - (timing.renderStart || timing.start)
|
|
397
|
+
);
|
|
398
|
+
this.info(
|
|
399
|
+
`Rendered ${finalResult.completedRoutes.size} pages in ${duration}ms`
|
|
400
|
+
);
|
|
401
|
+
if (typeof userOptions.onEvent === "function") {
|
|
402
|
+
try {
|
|
403
|
+
const r = userOptions.onEvent({
|
|
404
|
+
type: "build.ssg.end",
|
|
405
|
+
data: {
|
|
406
|
+
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
407
|
+
options: null,
|
|
408
|
+
// No specific rollup output options for static generation
|
|
409
|
+
bundle
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
if (r != null && typeof r === "object" && "then" in r) {
|
|
413
|
+
await r;
|
|
508
414
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
// Create a new Error object to avoid the "code" property issue
|
|
515
|
-
const finalError = new Error(errorToThrow.message);
|
|
516
|
-
finalError.stack = errorToThrow.stack;
|
|
517
|
-
finalError.cause = errorToThrow.cause;
|
|
518
|
-
// Copy any additional properties that might be needed
|
|
519
|
-
if (errorToThrow.name)
|
|
520
|
-
finalError.name = errorToThrow.name;
|
|
521
|
-
throw finalError;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
if (error != null) {
|
|
417
|
+
throw error;
|
|
418
|
+
} else {
|
|
419
|
+
throw new Error("Failed to emit build.ssg.end event");
|
|
522
420
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (process.env["NODE_ENV"] !== "production") {
|
|
424
|
+
this.warn(
|
|
425
|
+
`THIS BUILD IS NOT INTENDED FOR PRODUCTION (${process.env["NODE_ENV"]})`
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
timing.render = performance.now() - (timing.renderStart ?? timing.start);
|
|
429
|
+
} catch (error) {
|
|
430
|
+
panicError = handleError({
|
|
431
|
+
error,
|
|
432
|
+
logger,
|
|
433
|
+
panicThreshold: userOptions.panicThreshold});
|
|
434
|
+
} finally {
|
|
435
|
+
autoDiscoveredFiles = null;
|
|
436
|
+
serverManifest = void 0;
|
|
437
|
+
if (worker) {
|
|
438
|
+
try {
|
|
439
|
+
worker.removeAllListeners();
|
|
440
|
+
worker.terminate();
|
|
441
|
+
} catch (terminateError) {
|
|
442
|
+
}
|
|
443
|
+
worker = void 0;
|
|
444
|
+
globalWorker = void 0;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (panicError != null) {
|
|
448
|
+
const errorToThrow = panicError instanceof Error ? panicError : new Error(String(panicError));
|
|
449
|
+
const finalError = new Error(errorToThrow.message);
|
|
450
|
+
finalError.stack = errorToThrow.stack;
|
|
451
|
+
finalError.cause = errorToThrow.cause;
|
|
452
|
+
if (errorToThrow.name) finalError.name = errorToThrow.name;
|
|
453
|
+
throw finalError;
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
async closeBundle() {
|
|
457
|
+
if (this.environment.name === "server") {
|
|
458
|
+
try {
|
|
459
|
+
const { existsSync } = await import('node:fs');
|
|
460
|
+
const { join: join2, resolve } = await import('node:path');
|
|
461
|
+
const resolvedOutDir = this.environment.config.build?.outDir ? resolve(this.environment.config.root || userOptions.projectRoot, this.environment.config.build.outDir) : resolve(userOptions.projectRoot, userOptions.build.outDir);
|
|
462
|
+
const staticOutDir = join2(resolvedOutDir, userOptions.build.static || "static");
|
|
463
|
+
const staticVirtualDir = join2(staticOutDir, "_virtual");
|
|
464
|
+
if (existsSync(staticVirtualDir)) {
|
|
465
|
+
const { rmSync } = await import('node:fs');
|
|
466
|
+
rmSync(staticVirtualDir, { recursive: true, force: true });
|
|
467
|
+
if (userOptions.verbose) {
|
|
468
|
+
logger?.info(`[plugin.server] Cleaned up _virtual directory: ${staticVirtualDir}`);
|
|
553
469
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
// Send shutdown message
|
|
592
|
-
worker?.postMessage({
|
|
593
|
-
type: "SHUTDOWN",
|
|
594
|
-
id: "*",
|
|
595
|
-
});
|
|
596
|
-
}),
|
|
597
|
-
]);
|
|
598
|
-
}
|
|
599
|
-
catch (error) {
|
|
600
|
-
// If shutdown protocol fails, force terminate
|
|
601
|
-
this.warn("Worker shutdown protocol failed, forcing termination: " +
|
|
602
|
-
(error instanceof Error ? error.message : String(error)));
|
|
603
|
-
// Don't try to clean up listeners in error case - just force terminate
|
|
604
|
-
}
|
|
605
|
-
finally {
|
|
606
|
-
// Always force cleanup and termination
|
|
607
|
-
if (worker) {
|
|
608
|
-
try {
|
|
609
|
-
worker.removeAllListeners();
|
|
610
|
-
worker.terminate();
|
|
611
|
-
}
|
|
612
|
-
catch (terminateError) {
|
|
613
|
-
// Ignore termination errors
|
|
614
|
-
}
|
|
615
|
-
worker = undefined;
|
|
616
|
-
// Reset global worker since it's been terminated
|
|
617
|
-
globalWorker = undefined;
|
|
618
|
-
}
|
|
470
|
+
}
|
|
471
|
+
} catch (error) {
|
|
472
|
+
if (userOptions.verbose) {
|
|
473
|
+
logger?.warn(`[plugin.server] Failed to clean up _virtual directory: ${error}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (worker) {
|
|
478
|
+
try {
|
|
479
|
+
await Promise.race([
|
|
480
|
+
new Promise((resolve, reject) => {
|
|
481
|
+
const timeout = setTimeout(() => {
|
|
482
|
+
reject(new Error("Worker shutdown timeout"));
|
|
483
|
+
}, userOptions.workerShutdownTimeout);
|
|
484
|
+
const backupTimeout = setTimeout(() => {
|
|
485
|
+
reject(new Error("Worker shutdown backup timeout"));
|
|
486
|
+
}, Math.floor(userOptions.workerShutdownTimeout * 0.6));
|
|
487
|
+
const messageHandler = (message) => {
|
|
488
|
+
if (message.type === "SHUTDOWN_COMPLETE") {
|
|
489
|
+
if (userOptions.verbose) {
|
|
490
|
+
logger.info("Worker shutdown complete");
|
|
491
|
+
}
|
|
492
|
+
clearTimeout(timeout);
|
|
493
|
+
clearTimeout(backupTimeout);
|
|
494
|
+
worker?.removeListener("message", messageHandler);
|
|
495
|
+
worker?.removeAllListeners();
|
|
496
|
+
resolve();
|
|
497
|
+
} else if (message.type === "CLEANUP_COMPLETE") {
|
|
498
|
+
if (userOptions.verbose) {
|
|
499
|
+
logger.info("Worker cleanup completed during shutdown");
|
|
500
|
+
}
|
|
501
|
+
} else {
|
|
502
|
+
if (userOptions.verbose) {
|
|
503
|
+
logger.info(
|
|
504
|
+
"Worker is still busy, received message " + message?.type
|
|
505
|
+
);
|
|
506
|
+
}
|
|
619
507
|
}
|
|
508
|
+
};
|
|
509
|
+
worker?.on("message", messageHandler);
|
|
510
|
+
worker?.postMessage({
|
|
511
|
+
type: "SHUTDOWN",
|
|
512
|
+
id: "*"
|
|
513
|
+
});
|
|
514
|
+
})
|
|
515
|
+
]);
|
|
516
|
+
} catch (error) {
|
|
517
|
+
this.warn(
|
|
518
|
+
"Worker shutdown protocol failed, forcing termination: " + (error instanceof Error ? error.message : String(error))
|
|
519
|
+
);
|
|
520
|
+
} finally {
|
|
521
|
+
if (worker) {
|
|
522
|
+
try {
|
|
523
|
+
worker.removeAllListeners();
|
|
524
|
+
worker.terminate();
|
|
525
|
+
} catch (terminateError) {
|
|
620
526
|
}
|
|
621
|
-
|
|
622
|
-
|
|
527
|
+
worker = void 0;
|
|
528
|
+
globalWorker = void 0;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
};
|
|
623
534
|
};
|
|
535
|
+
|
|
536
|
+
export { reactStaticPlugin };
|
|
537
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLnNlcnZlci5qcyIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcGx1Z2luL3JlYWN0LXN0YXRpYy9wbHVnaW4uc2VydmVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogcGx1Z2luLnRzXG4gKlxuICogUFVSUE9TRTogTWFpbiBWaXRlIHBsdWdpbiBmb3IgUmVhY3QgU2VydmVyIENvbXBvbmVudHMgKFJTQykgc3RhdGljIHNpdGUgZ2VuZXJhdGlvblxuICpcbiAqIFRoaXMgbW9kdWxlOlxuICogMS4gT3JjaGVzdHJhdGVzIHRoZSBlbnRpcmUgc3RhdGljIHNpdGUgZ2VuZXJhdGlvbiBwcm9jZXNzXG4gKiAyLiBNYW5hZ2VzIHRoZSBsaWZlY3ljbGUgb2YgdGhlIFJTQyByZW5kZXJpbmcgcHJvY2Vzc1xuICogMy4gSGFuZGxlcyBmaWxlIHdyaXRpbmcgZm9yIGJvdGggaW5pdGlhbCBwYWdlIGxvYWRzIGFuZCBjbGllbnQtc2lkZSBuYXZpZ2F0aW9uXG4gKiAgICAtIFdyaXRlcyAuaHRtbCBmaWxlcyBmb3IgaW5pdGlhbCBwYWdlIGxvYWRzIChjb21wbGV0ZSBIVE1MIGRvY3VtZW50KVxuICogICAgLSBXcml0ZXMgLnJzYyBmaWxlcyBmb3IgY2xpZW50LXNpZGUgbmF2aWdhdGlvbiAoUlNDIGNvbnRlbnQgb25seSlcbiAqIDQuIFByb3ZpZGVzIGhvb2tzIGZvciBWaXRlIHRvIGludGVncmF0ZSB3aXRoIHRoZSBidWlsZCBwcm9jZXNzXG4gKiA1LiBNYW5hZ2VzIHdvcmtlciB0aHJlYWRzIGZvciBwYXJhbGxlbCByZW5kZXJpbmdcbiAqIDYuIEhhbmRsZXMgZXJyb3IgcmVwb3J0aW5nIGFuZCBtZXRyaWNzIGNvbGxlY3Rpb25cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFdvcmtlciB9IGZyb20gXCJub2RlOndvcmtlcl90aHJlYWRzXCI7XG5pbXBvcnQge1xuICB0eXBlIENvbmZpZ0VudixcbiAgdHlwZSBMb2dnZXIsXG4gIHR5cGUgTWFuaWZlc3QsXG4gIHR5cGUgTWFuaWZlc3RDaHVuayxcbiAgdHlwZSBSZXNvbHZlZENvbmZpZyxcbiAgY3JlYXRlTG9nZ2VyLFxufSBmcm9tIFwidml0ZVwiO1xuaW1wb3J0IHsgcmVzb2x2ZU9wdGlvbnMgfSBmcm9tIFwiLi4vY29uZmlnL3Jlc29sdmVPcHRpb25zLmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVCdWlsZExvYWRlciB9IGZyb20gXCIuL2NyZWF0ZUJ1aWxkTG9hZGVyLnNlcnZlci5qc1wiO1xuaW1wb3J0IHR5cGUge1xuICBCdWlsZFRpbWluZyxcbiAgUmVuZGVyUGFnZXNSZXN1bHQsXG4gIEF1dG9EaXNjb3ZlcmVkRmlsZXMsXG4gIFZpdGVQbHVnaW5Gbixcbn0gZnJvbSBcIi4uL3R5cGVzLmpzXCI7XG5pbXBvcnQgeyByZW5kZXJQYWdlc0JhdGNoZWQgfSBmcm9tIFwiLi9yZW5kZXJQYWdlc0JhdGNoZWQuanNcIjtcbmltcG9ydCB7IHJlbmRlclBhZ2VzIGFzIHJlbmRlclBhZ2VzU2VxdWVudGlhbCB9IGZyb20gXCIuL3JlbmRlclBhZ2VzLmpzXCI7XG5pbXBvcnQgeyBnZXRCdW5kbGVNYW5pZmVzdCB9IGZyb20gXCIuLi9oZWxwZXJzL2dldEJ1bmRsZU1hbmlmZXN0LmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVXb3JrZXIgfSBmcm9tIFwiLi4vd29ya2VyL2NyZWF0ZVdvcmtlci5qc1wiO1xuaW1wb3J0IHtcbiAgc2VyaWFsaXplZE9wdGlvbnMsXG4gIHNlcmlhbGl6ZVJlc29sdmVkQ29uZmlnLFxufSBmcm9tIFwiLi4vaGVscGVycy9zZXJpYWxpemVVc2VyT3B0aW9ucy5qc1wiO1xuaW1wb3J0IHsgcGVyZm9ybWFuY2UgfSBmcm9tIFwibm9kZTpwZXJmX2hvb2tzXCI7XG5pbXBvcnQgeyBiYXNlVVJMIH0gZnJvbSBcIi4uL3V0aWxzL2VudlVybHMubm9kZS5qc1wiO1xuaW1wb3J0IHsgaGFuZGxlRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3IvaGFuZGxlRXJyb3IuanNcIjtcbmltcG9ydCB7IHNob3VsZENhdXNlUGFuaWMgfSBmcm9tIFwiLi4vZXJyb3IvcGFuaWNUaHJlc2hvbGRIYW5kbGVyLmpzXCI7XG5pbXBvcnQgeyByZW5kZXJQYWdlIH0gZnJvbSBcIi4vcmVuZGVyUGFnZS5zZXJ2ZXIuanNcIjtcbmltcG9ydCB7IHRlbXBvcmFyeVJlZmVyZW5jZXMgfSBmcm9tIFwiLi90ZW1wb3JhcnlSZWZlcmVuY2VzLnNlcnZlci5qc1wiO1xuaW1wb3J0IHsgY29uZmlndXJlUHJldmlld1NlcnZlciB9IGZyb20gXCIuL2NvbmZpZ3VyZVByZXZpZXdTZXJ2ZXIuanNcIjtcbmltcG9ydCB7IGVudlByZWZpeEZyb21Db25maWcgfSBmcm9tIFwiLi4vY29uZmlnL2VudlByZWZpeEZyb21Db25maWcuanNcIjtcblxuaW1wb3J0IHsgcHJvY2Vzc0Nzc0ZpbGVzRm9yUGFnZXMgfSBmcm9tIFwiLi9wcm9jZXNzQ3NzRmlsZXNGb3JQYWdlcy5qc1wiO1xuaW1wb3J0IHsgY3JlYXRlV29ya2VyU3RhcnR1cE1ldHJpY3MgfSBmcm9tIFwiLi4vbWV0cmljcy9jcmVhdGVXb3JrZXJTdGFydHVwTWV0cmljcy5qc1wiO1xuaW1wb3J0IHsgdHJ5TWFuaWZlc3QgfSBmcm9tIFwiLi4vaGVscGVycy90cnlNYW5pZmVzdC5qc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IHJlc29sdmVBdXRvRGlzY292ZXIgfSBmcm9tIFwiLi4vY29uZmlnL2F1dG9EaXNjb3Zlci9yZXNvbHZlQXV0b0Rpc2NvdmVyLmpzXCI7XG5pbXBvcnQgeyBhc3NlcnRSZWFjdFNlcnZlciB9IGZyb20gXCIuLi9jb25maWcvZ2V0Q29uZGl0aW9uLmpzXCI7XG5pbXBvcnQgeyB0b0Vycm9yIH0gZnJvbSBcIi4uL2Vycm9yL3RvRXJyb3IuanNcIjtcblxuYXNzZXJ0UmVhY3RTZXJ2ZXIoKTtcblxuLyoqXG4gKiBNYWluIGVudHJ5cG9pbnQgZm9yIHRoZSBzdGF0aWMgcGx1Z2luLlxuICpcbiAqIFRoaXMgcGx1Z2luIGlzIHJlc3BvbnNpYmxlIGZvcjpcbiAqIDEuIE9yY2hlc3RyYXRpbmcgdGhlIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gcHJvY2Vzc1xuICogMi4gSGFuZGxpbmcgdGhlIGxpZmVjeWNsZSBvZiB0aGUgUlNDIHJlbmRlcmluZyBwcm9jZXNzIChtYWluIHRocmVhZClcbiAqIDMuIFdyaXRpbmcgLmh0bWwgZmlsZXMgZm9yIGluaXRpYWwgcGFnZSBsb2FkcyAoY29tcGxldGUgSFRNTCBkb2N1bWVudClcbiAqIDQuIFdyaXRpbmcgLnJzYyBmaWxlcyBmb3IgY2xpZW50LXNpZGUgbmF2aWdhdGlvbiAoUlNDIGNvbnRlbnQgb25seSlcbiAqIDUuIE1hbmFnaW5nIHdvcmtlciB0aHJlYWRzIGZvciBwYXJhbGxlbCByZW5kZXJpbmcgKGh0bWwgd29ya2VyKVxuICogNi4gSGFuZGxpbmcgZXJyb3IgcmVwb3J0aW5nIGFuZCBtZXRyaWNzIGNvbGxlY3Rpb25cbiAqL1xuLy8gR2xvYmFsIHdvcmtlciBpbnN0YW5jZSB0byBwcmV2ZW50IGR1cGxpY2F0ZSBjcmVhdGlvbiBhY3Jvc3MgcGx1Z2luIGluc3RhbmNlc1xubGV0IGdsb2JhbFdvcmtlcjogV29ya2VyIHwgdW5kZWZpbmVkO1xuXG5leHBvcnQgY29uc3QgcmVhY3RTdGF0aWNQbHVnaW46IFZpdGVQbHVnaW5GbiA9IGZ1bmN0aW9uIF9yZWFjdFN0YXRpY1BsdWdpbihcbiAgb3B0aW9uc1xuKSB7XG4gIGxldCB3b3JrZXI6IFdvcmtlciB8IHVuZGVmaW5lZDtcbiAgbGV0IGxvZ2dlcjogTG9nZ2VyO1xuICBsZXQgcmVzb2x2ZWRDb25maWc6IFJlc29sdmVkQ29uZmlnO1xuICBsZXQgYXV0b0Rpc2NvdmVyZWRGaWxlczogQXV0b0Rpc2NvdmVyZWRGaWxlcyB8IG51bGwgPSBudWxsO1xuICBsZXQgc2VydmVyTWFuaWZlc3Q6IE1hbmlmZXN0IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICBsZXQgY29uZmlnRW52OiBDb25maWdFbnYgfCB1bmRlZmluZWQ7XG4gIGNvbnN0IHRpbWluZzogQnVpbGRUaW1pbmcgPSB7XG4gICAgc3RhcnQ6IHBlcmZvcm1hbmNlLm5vdygpLFxuICAgIGNvbmZpZ1Jlc29sdmVkOiAwLFxuICAgIGJ1aWxkU3RhcnQ6IDAsXG4gICAgcmVuZGVyU3RhcnQ6IDAsXG4gIH07XG5cbiAgY29uc3QgcmVzb2x2ZWRPcHRpb25zID0gcmVzb2x2ZU9wdGlvbnMob3B0aW9ucyk7XG4gIGlmIChyZXNvbHZlZE9wdGlvbnMudHlwZSA9PT0gXCJlcnJvclwiKSB7XG4gICAgdGhyb3cgcmVzb2x2ZWRPcHRpb25zLmVycm9yO1xuICB9XG4gIGNvbnN0IHVzZXJPcHRpb25zID0gcmVzb2x2ZWRPcHRpb25zLnVzZXJPcHRpb25zO1xuXG4gIHJldHVybiB7XG4gICAgbmFtZTogXCJ2aXRlOnBsdWdpbi1yZWFjdC1zZXJ2ZXIvc2VydmVyLXN0YXRpY1wiLFxuICAgIGVuZm9yY2U6IFwicG9zdFwiLFxuICAgIGFwaToge1xuICAgICAgbWV0YTogeyB0aW1pbmcgfSxcbiAgICB9LFxuICAgIGFzeW5jIGNvbmZpZyhfY29uZmlnLCB2aXRlQ29uZmlnRW52KSB7XG4gICAgICBjb25maWdFbnYgPSB2aXRlQ29uZmlnRW52O1xuICAgIH0sXG4gICAgYXBwbHlUb0Vudmlyb25tZW50KHBhcnRpYWxFbnZpcm9ubWVudCkge1xuXG4gICAgICBpZiAoXG4gICAgICAgIFtcInNlcnZlclwiXS5pbmNsdWRlcyhcbiAgICAgICAgICBwYXJ0aWFsRW52aXJvbm1lbnQubmFtZSBhcyBcImNsaWVudFwiIHwgXCJzZXJ2ZXJcIiB8IFwic3NyXCJcbiAgICAgICAgKVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG4gICAgYXN5bmMgY29uZmlnUmVzb2x2ZWQoY29uZmlnKSB7XG4gICAgICByZXNvbHZlZENvbmZpZyA9IGNvbmZpZztcbiAgICAgIGlmICghbG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlciA9IGNvbmZpZy5jdXN0b21Mb2dnZXIgPz8gY3JlYXRlTG9nZ2VyKCk7XG4gICAgICB9XG4gICAgICBjb25zdCBhdXRvRGlzY292ZXJSZXN1bHQgPSBhd2FpdCByZXNvbHZlQXV0b0Rpc2NvdmVyKHtcbiAgICAgICAgY29uZmlnOiBjb25maWcsXG4gICAgICAgIGNvbmZpZ0VudjogY29uZmlnRW52ISxcbiAgICAgICAgdXNlck9wdGlvbnMsXG4gICAgICAgIGxvZ2dlcixcbiAgICAgIH0pO1xuICAgICAgaWYgKGF1dG9EaXNjb3ZlclJlc3VsdC50eXBlID09PSBcImVycm9yXCIpIHtcbiAgICAgICAgdGhyb3cgYXV0b0Rpc2NvdmVyUmVzdWx0LmVycm9yO1xuICAgICAgfVxuICAgICAgYXV0b0Rpc2NvdmVyZWRGaWxlcyA9IGF1dG9EaXNjb3ZlclJlc3VsdC5hdXRvRGlzY292ZXJlZEZpbGVzO1xuICAgIH0sXG4gICAgYXN5bmMgYnVpbGRTdGFydCgpIHtcbiAgICAgIGlmICghbG9nZ2VyKSB7XG4gICAgICAgIGxvZ2dlciA9IHRoaXMuZW52aXJvbm1lbnQubG9nZ2VyO1xuICAgICAgfVxuICAgICAgdGltaW5nLmJ1aWxkU3RhcnQgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgIGlmICh1c2VyT3B0aW9ucy5vbkV2ZW50ICYmIGF1dG9EaXNjb3ZlcmVkRmlsZXMpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB1c2VyT3B0aW9ucy5vbkV2ZW50KHtcbiAgICAgICAgICAgIHR5cGU6IFwiYnVpbGQuc3RhcnRcIixcbiAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgcGFnZXM6IEFycmF5LmZyb20oYXV0b0Rpc2NvdmVyZWRGaWxlcy51cmxNYXAua2V5cygpKSxcbiAgICAgICAgICAgICAgZmlsZXM6IGF1dG9EaXNjb3ZlcmVkRmlsZXMsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnN0IHBhbmljRXJyb3IgPSBoYW5kbGVFcnJvcih7XG4gICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgIGxvZ2dlcjogbG9nZ2VyLFxuICAgICAgICAgICAgcGFuaWNUaHJlc2hvbGQ6IHVzZXJPcHRpb25zLnBhbmljVGhyZXNob2xkLFxuICAgICAgICAgICAgY29udGV4dDogXCJidWlsZFN0YXJ0XCIsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgICAgd29ya2VyPy50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgIHRocm93IHBhbmljRXJyb3I7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZXJyb3IobmV3IEVycm9yKFwiRmFpbGVkIHRvIGVtaXQgYnVpbGQuc3RhcnQgZXZlbnRcIikpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG5cbiAgICAvLyB0aGUgcHJldmlldyBzZXJ2ZXIgaGVscHMgdG8gdmlldyB0aGUgZ2VuZXJhdGVkIHN0YXRpYyBmb2xkZXIsIGJ1dCBvbmx5IHdoZW4gdGhlIHN0YXRpYyBwbHVnaW4gaXMgZW5hYmxlZFxuICAgIC8vIGlmIG5vIGJ1aWxkLnBhZ2VzLCB0aGVuIHRoZSBwcmV2aWV3IHNlcnZlciB3aWxsIGluc3RlYWQgdXNlIGRlZmF1bHQgdml0ZSBwcmV2aWV3IHNlcnZlclxuICAgIC8vIGl0IHdvcmtzIHRoZSBzYW1lIHVuZGVyIGJvdGggY29uZGl0aW9uc1xuICAgIGFzeW5jIGNvbmZpZ3VyZVByZXZpZXdTZXJ2ZXIoc2VydmVyKSB7XG4gICAgICBsb2dnZXIgPSBzZXJ2ZXIuY29uZmlnLmN1c3RvbUxvZ2dlciB8fCBzZXJ2ZXIuY29uZmlnLmxvZ2dlcjtcbiAgICAgIGNvbmZpZ3VyZVByZXZpZXdTZXJ2ZXIoe1xuICAgICAgICBzZXJ2ZXIsXG4gICAgICAgIHVzZXJPcHRpb25zLFxuICAgICAgfSk7XG4gICAgfSxcblxuICAgIGFzeW5jIHJlbmRlclN0YXJ0KCkge1xuICAgICAgdGltaW5nLnJlbmRlclN0YXJ0ID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgfSxcbiAgICBnZW5lcmF0ZUJ1bmRsZShfb3B0aW9ucywgYnVuZGxlKSB7XG4gICAgICAvLyBGaWx0ZXIgb3V0IHVubmVjZXNzYXJ5IF92aXJ0dWFsIGZpbGVzIGZyb20gdGhlIGJ1bmRsZVxuICAgICAgLy8gS2VlcCBkeW5hbWljLWltcG9ydC1oZWxwZXIuanMgc2luY2UgaXQncyBuZWVkZWQgZm9yIGR5bmFtaWMgaW1wb3J0c1xuICAgICAgLy8gTm90ZTogU3RhdGljIGJ1aWxkcyBhcmUgaGFuZGxlZCBieSBwbHVnaW4uY2xpZW50LnRzLCB0aGlzIG9ubHkgaGFuZGxlcyBzZXJ2ZXIgYnVpbGRzXG4gICAgICBpZiAodGhpcy5lbnZpcm9ubWVudC5uYW1lID09PSBcInNlcnZlclwiKSB7XG4gICAgICAgIGNvbnN0IGtleXNUb0RlbGV0ZTogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgZm9yIChjb25zdCBba2V5LCBjaHVua10gb2YgT2JqZWN0LmVudHJpZXMoYnVuZGxlKSkge1xuICAgICAgICAgIGlmIChjaHVuay50eXBlID09PSBcImNodW5rXCIpIHtcbiAgICAgICAgICAgIC8vIENoZWNrIGZpbGVOYW1lLCBrZXksIG1vZHVsZUlkcywgYW5kIGZhY2FkZU1vZHVsZUlkIGZvciBfdmlydHVhbFxuICAgICAgICAgICAgY29uc3QgaXNWaXJ0dWFsID0gXG4gICAgICAgICAgICAgIGNodW5rLmZpbGVOYW1lPy5pbmNsdWRlcyhcIl92aXJ0dWFsXCIpIHx8XG4gICAgICAgICAgICAgIGtleS5pbmNsdWRlcyhcIl92aXJ0dWFsXCIpIHx8XG4gICAgICAgICAgICAgIGNodW5rLmZhY2FkZU1vZHVsZUlkPy5pbmNsdWRlcyhcIl92aXJ0dWFsXCIpIHx8XG4gICAgICAgICAgICAgIGNodW5rLm1vZHVsZUlkcz8uc29tZShpZCA9PiBpZC5pbmNsdWRlcyhcIl92aXJ0dWFsXCIpKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgLy8gS2VlcCBkeW5hbWljLWltcG9ydC1oZWxwZXIuanMgLSBpdCdzIG5lZWRlZCBmb3IgZHluYW1pYyBpbXBvcnRzXG4gICAgICAgICAgICBjb25zdCBpc0R5bmFtaWNJbXBvcnRIZWxwZXIgPSBcbiAgICAgICAgICAgICAgY2h1bmsuZmlsZU5hbWU/LmluY2x1ZGVzKFwiZHluYW1pYy1pbXBvcnQtaGVscGVyXCIpIHx8XG4gICAgICAgICAgICAgIGtleS5pbmNsdWRlcyhcImR5bmFtaWMtaW1wb3J0LWhlbHBlclwiKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgaWYgKGlzVmlydHVhbCAmJiAhaXNEeW5hbWljSW1wb3J0SGVscGVyKSB7XG4gICAgICAgICAgICAgIGtleXNUb0RlbGV0ZS5wdXNoKGtleSk7XG4gICAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyPy5pbmZvKGBbcGx1Z2luLnNlcnZlcl0gRmlsdGVyZWQgb3V0IHZpcnR1YWwgZmlsZTogJHtjaHVuay5maWxlTmFtZSB8fCBrZXl9IChtb2R1bGVJZDogJHtjaHVuay5mYWNhZGVNb2R1bGVJZCB8fCBjaHVuay5tb2R1bGVJZHM/LlswXX0pYCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gRGVsZXRlIGFmdGVyIGl0ZXJhdGlvbiB0byBhdm9pZCBtb2RpZnlpbmcgd2hpbGUgaXRlcmF0aW5nXG4gICAgICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXNUb0RlbGV0ZSkge1xuICAgICAgICAgIGRlbGV0ZSBidW5kbGVba2V5XTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG5cbiAgICBhc3luYyB3cml0ZUJ1bmRsZShfb3B0aW9ucywgYnVuZGxlKSB7XG4gICAgICAvLyBPbmx5IGV4ZWN1dGUgc3RhdGljIGdlbmVyYXRpb24gZm9yIHRoZSBzZXJ2ZXIgZW52aXJvbm1lbnRcbiAgICAgIGlmICh0aGlzLmVudmlyb25tZW50Lm5hbWUgIT09IFwic2VydmVyXCIpIHtcbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtwbHVnaW4uc2VydmVyXSBTa2lwcGluZyBzdGF0aWMgZ2VuZXJhdGlvbiBmb3IgZW52aXJvbm1lbnQ6ICR7dGhpcy5lbnZpcm9ubWVudC5uYW1lfWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgbGV0IHBhbmljRXJyb3I6IEVycm9yIHwgbnVsbCA9IG51bGw7XG4gICAgICBsZXQgYnVuZGxlTWFuaWZlc3Q6XG4gICAgICAgIHwge1xuICAgICAgICAgICAgW2tleTogc3RyaW5nXTogTWFuaWZlc3RDaHVuayAmIHtcbiAgICAgICAgICAgICAgc291cmNlOiBzdHJpbmc7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gICAgICBpZiAoIWxvZ2dlcikge1xuICAgICAgICBsb2dnZXIgPSB0aGlzLmVudmlyb25tZW50LmxvZ2dlcjtcbiAgICAgIH1cblxuICAgICAgLy8gaGFuZGxlIHRoZSBidW5kbGUgbWFuaWZlc3RcbiAgICAgIHRyeSB7XG4gICAgICAgIGJ1bmRsZU1hbmlmZXN0ID0gZ2V0QnVuZGxlTWFuaWZlc3Q8ZmFsc2U+KHtcbiAgICAgICAgICBidW5kbGUsXG4gICAgICAgICAgbm9ybWFsaXplcjogdXNlck9wdGlvbnMubm9ybWFsaXplcixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoYXQgd2UgaGF2ZSBhIG1hbmlmZXN0XG4gICAgICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9XG4gICAgICAgICAgdHlwZW9mIHJlc29sdmVkQ29uZmlnLmJ1aWxkLm1hbmlmZXN0ID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICA/IHJlc29sdmVkQ29uZmlnLmJ1aWxkLm1hbmlmZXN0XG4gICAgICAgICAgICA6IFwiLnZpdGUvbWFuaWZlc3QuanNvblwiO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgIWJ1bmRsZU1hbmlmZXN0W21hbmlmZXN0UGF0aF0gfHxcbiAgICAgICAgICAhKFwic291cmNlXCIgaW4gYnVuZGxlTWFuaWZlc3RbbWFuaWZlc3RQYXRoXSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2VydmVyIG1hbmlmZXN0IG5vdCBmb3VuZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHBhcnNlIHRoZSBtYW5pZmVzdFxuICAgICAgICBzZXJ2ZXJNYW5pZmVzdCA9IEpTT04ucGFyc2UoXG4gICAgICAgICAgYnVuZGxlTWFuaWZlc3RbbWFuaWZlc3RQYXRoXS5zb3VyY2UgYXMgc3RyaW5nXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoYXQgd2UgaGF2ZSBhIG1hbmlmZXN0XG4gICAgICAgIGlmICghc2VydmVyTWFuaWZlc3QpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGYWlsZWQgdG8gcGFyc2Ugc2VydmVyIG1hbmlmZXN0XCIpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBwYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgIGVycm9yLFxuICAgICAgICAgIGxvZ2dlcjogbG9nZ2VyLFxuICAgICAgICAgIHBhbmljVGhyZXNob2xkOiB1c2VyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgICAgICBjb250ZXh0OiBcIndyaXRlQnVuZGxlKGJ1bmRsZU1hbmlmZXN0KVwiLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgIHRocm93IHBhbmljRXJyb3I7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmFpbGVkIHRvIGdldCBidW5kbGUgbWFuaWZlc3RcIik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3Qgc3RhdGljTWFuaWZlc3RSZXN1bHQgPSBhd2FpdCB0cnlNYW5pZmVzdCh7XG4gICAgICAgICAgcm9vdDogdXNlck9wdGlvbnMucHJvamVjdFJvb3QsXG4gICAgICAgICAgb3V0RGlyOiBqb2luKHVzZXJPcHRpb25zLmJ1aWxkLm91dERpciwgdXNlck9wdGlvbnMuYnVpbGQuc3RhdGljKSxcbiAgICAgICAgICBtYW5pZmVzdFBhdGg6IHJlc29sdmVkQ29uZmlnLmJ1aWxkLm1hbmlmZXN0LFxuICAgICAgICAgIHNzck1hbmlmZXN0OiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChzdGF0aWNNYW5pZmVzdFJlc3VsdC50eXBlID09PSBcImVycm9yXCIpIHtcbiAgICAgICAgICB0aHJvdyBzdGF0aWNNYW5pZmVzdFJlc3VsdC5lcnJvcjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzdGF0aWNNYW5pZmVzdCA9IHN0YXRpY01hbmlmZXN0UmVzdWx0Lm1hbmlmZXN0O1xuICAgICAgICBcbiAgICAgICAgLy8gRG9uJ3QgY3JlYXRlIGhlbHBlciBmaWxlIC0gbGV0IHJlc29sdmVWaXJ0dWFsQW5kTm9kZU1vZHVsZXMgc2hpbSBoYW5kbGUgaXRcbiAgICAgICAgLy8gU2FtZSBhcHByb2FjaCBhcyBjbGllbnQgZW52aXJvbm1lbnQgLSBubyBzcGVjaWFsIGZpbGUgbmVlZGVkXG4gICAgICAgIFxuICAgICAgICBjb25zdCBidWlsZExvYWRlciA9IGNyZWF0ZUJ1aWxkTG9hZGVyKFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHVzZXJPcHRpb25zOiB1c2VyT3B0aW9ucyxcbiAgICAgICAgICAgIHNlcnZlck1hbmlmZXN0OiBzZXJ2ZXJNYW5pZmVzdCA/PyB7fSxcbiAgICAgICAgICAgIHN0YXRpY01hbmlmZXN0OiBzdGF0aWNNYW5pZmVzdCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGJ1bmRsZSxcbiAgICAgICAgICB0ZW1wb3JhcnlSZWZlcmVuY2VzLFxuICAgICAgICAgIGxvZ2dlclxuICAgICAgICApO1xuICAgICAgICAvLyBDcmVhdGUgQ1NTIHByb3BzIGZvciBlYWNoIENTUyBmaWxlXG4gICAgICAgIGNvbnN0IHsgY3NzRmlsZXNCeVBhZ2UsIGdsb2JhbENzcyB9ID0gcHJvY2Vzc0Nzc0ZpbGVzRm9yUGFnZXMoe1xuICAgICAgICAgIHVzZXJPcHRpb25zLFxuICAgICAgICAgIGF1dG9EaXNjb3ZlcmVkRmlsZXMsXG4gICAgICAgICAgc2VydmVyTWFuaWZlc3QsXG4gICAgICAgICAgc3RhdGljTWFuaWZlc3QsXG4gICAgICAgICAgYnVuZGxlLFxuICAgICAgICAgIGxvZ2dlcixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbcGx1Z2luLnNlcnZlcl0gY3NzRmlsZXNCeVBhZ2Ugc2l6ZTogJHtjc3NGaWxlc0J5UGFnZS5zaXplfWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGZvciAoY29uc3QgW3JvdXRlLCBjc3NNYXBdIG9mIGNzc0ZpbGVzQnlQYWdlLmVudHJpZXMoKSkge1xuICAgICAgICAgICAgbG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgIGBbcGx1Z2luLnNlcnZlcl0gUm91dGUgJHtyb3V0ZX06ICR7Y3NzTWFwLnNpemV9IENTUyBmaWxlc2BcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBpbmRleEh0bWwgPSBzdGF0aWNNYW5pZmVzdD8uW1wiaW5kZXguaHRtbFwiXT8uZmlsZTtcbiAgICAgICAgY29uc3Qgc2VydmVyUGlwZWFibGVTdHJlYW1PcHRpb25zID0ge1xuICAgICAgICAgIC4uLnVzZXJPcHRpb25zLnNlcnZlclBpcGVhYmxlU3RyZWFtT3B0aW9ucyxcbiAgICAgICAgICBib290c3RyYXBNb2R1bGVzOiBbXG4gICAgICAgICAgICAuLi4oaW5kZXhIdG1sID8gW2Jhc2VVUkwoaW5kZXhIdG1sKV0gOiBbXSksXG4gICAgICAgICAgICAuLi4odXNlck9wdGlvbnMuc2VydmVyUGlwZWFibGVTdHJlYW1PcHRpb25zPy5ib290c3RyYXBNb2R1bGVzID8/XG4gICAgICAgICAgICAgIFtdKSxcbiAgICAgICAgICBdLFxuICAgICAgICB9O1xuICAgICAgICB1c2VyT3B0aW9ucy5zZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnMgPSBzZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnM7XG4gICAgICAgIGNvbnN0IGNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucyA9IHtcbiAgICAgICAgICAuLi51c2VyT3B0aW9ucy5jbGllbnRQaXBlYWJsZVN0cmVhbU9wdGlvbnMsXG4gICAgICAgICAgYm9vdHN0cmFwTW9kdWxlczogW1xuICAgICAgICAgICAgLi4uKGluZGV4SHRtbCA/IFtiYXNlVVJMKGluZGV4SHRtbCldIDogW10pLFxuICAgICAgICAgICAgLi4uKHVzZXJPcHRpb25zLmNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucz8uYm9vdHN0cmFwTW9kdWxlcyA/P1xuICAgICAgICAgICAgICBbXSksXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgICAgLy8gR2V0IHJvdXRlcyBmb3Igd29ya2VyIGNvbmZpZ3VyYXRpb25cbiAgICAgICAgY29uc3Qgcm91dGVzID0gIWF1dG9EaXNjb3ZlcmVkRmlsZXNcbiAgICAgICAgICA/IFtdXG4gICAgICAgICAgOiBBcnJheS5mcm9tKGF1dG9EaXNjb3ZlcmVkRmlsZXMhLnVybE1hcC5rZXlzKCkpO1xuXG4gICAgICAgIC8vIElmIG5vIHBhZ2VzIHRvIGdlbmVyYXRlLCBza2lwIHN0YXRpYyBnZW5lcmF0aW9uIGVudGlyZWx5IChpbmNsdWRpbmcgd29ya2VyIGNyZWF0aW9uKVxuICAgICAgICBpZiAocm91dGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGxvZ2dlcj8uaW5mbyhcbiAgICAgICAgICAgIFwiW3BsdWdpbi5zZXJ2ZXJdIE5vIHBhZ2VzIHRvIGdlbmVyYXRlLCBza2lwcGluZyBzdGF0aWMgZ2VuZXJhdGlvblwiXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZXJpYWxpemVkVXNlck9wdGlvbnMgPSBzZXJpYWxpemVkT3B0aW9ucyhcbiAgICAgICAgICB1c2VyT3B0aW9ucyxcbiAgICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzIVxuICAgICAgICApO1xuICAgICAgICAvLyBDcmVhdGUgSFRNTCB3b3JrZXIgZm9yIEhUTUwgZ2VuZXJhdGlvblxuICAgICAgICAvLyBJTVBPUlRBTlQ6IFdlIGNyZWF0ZSBhIG5ldyB3b3JrZXIgZm9yIGVhY2ggcGFnZSByZW5kZXIgdG8gZW5zdXJlIGNvbXBsZXRlbHkgY2xlYW4gc3RhdGVcbiAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyByYWNlIGNvbmRpdGlvbnMgd2hlcmUgd29ya2VyIHN0YXRlIHBlcnNpc3RzIGJldHdlZW4gcmVuZGVyc1xuICAgICAgICAvLyBHdWFyZCBhZ2FpbnN0IGR1cGxpY2F0ZSB3b3JrZXIgY3JlYXRpb24gaWYgcGx1Z2luIGlzIGluc3RhbnRpYXRlZCBtdWx0aXBsZSB0aW1lc1xuICAgICAgICBpZiAoZ2xvYmFsV29ya2VyKSB7XG4gICAgICAgICAgbG9nZ2VyPy53YXJuKFwiW3BsdWdpbi5zZXJ2ZXJdIEdsb2JhbCB3b3JrZXIgYWxyZWFkeSBleGlzdHMsIHJldXNpbmcgZXhpc3Rpbmcgd29ya2VyXCIpO1xuICAgICAgICAgIHdvcmtlciA9IGdsb2JhbFdvcmtlcjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCB3b3JrZXJTdGFydFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgICAgICBjb25zdCB2aXRlRW52UHJlZml4ID0gZW52UHJlZml4RnJvbUNvbmZpZyhyZXNvbHZlZENvbmZpZyk7XG4gICAgICAgICAgY29uc3Qgcm91dGVDb3VudCA9IGF1dG9EaXNjb3ZlcmVkRmlsZXM/LnVybE1hcC5zaXplID8/IDA7XG4gICAgICAgICAgY29uc3QgbWF4TGlzdGVuZXJzID0gcm91dGVDb3VudCArIDE7XG4gICAgICAgICAgY29uc3Qgd29ya2VyUmVzdWx0ID0gYXdhaXQgY3JlYXRlV29ya2VyKHtcbiAgICAgICAgICAgIHByb2plY3RSb290OiB1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCxcbiAgICAgICAgICAgIHdvcmtlclBhdGg6IHVzZXJPcHRpb25zLmh0bWxXb3JrZXJQYXRoLFxuICAgICAgICAgICAgY3VycmVudENvbmRpdGlvbjogXCJyZWFjdC1zZXJ2ZXJcIixcbiAgICAgICAgICAgIHJldmVyc2VDb25kaXRpb246IFwicmVhY3QtY2xpZW50XCIsIC8vIEhUTUwgd29ya2VyIG5lZWRzIHJlYWN0LWNsaWVudCBmb3IgcmVhY3QtZG9tL3NlcnZlclxuICAgICAgICAgICAgbWF4TGlzdGVuZXJzOiBtYXhMaXN0ZW5lcnMsXG4gICAgICAgICAgICBlbnZQcmVmaXg6IHZpdGVFbnZQcmVmaXgsXG4gICAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICAgIHdvcmtlckRhdGE6IHtcbiAgICAgICAgICAgICAgcmVzb2x2ZWRDb25maWc6IHNlcmlhbGl6ZVJlc29sdmVkQ29uZmlnKHJlc29sdmVkQ29uZmlnKSxcbiAgICAgICAgICAgICAgdXNlck9wdGlvbnM6IHNlcmlhbGl6ZWRVc2VyT3B0aW9ucyxcbiAgICAgICAgICAgICAgY29uZmlnRW52LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAod29ya2VyUmVzdWx0LnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgICAgICAgICAgaWYgKHdvcmtlclJlc3VsdC5lcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgICAgIHRocm93IHdvcmtlclJlc3VsdC5lcnJvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlYWN0IHN0YXRpYyBwbHVnaW4gZmFpbGVkIHRvIGNyZWF0ZSB3b3JrZXJcIik7XG4gICAgICAgICAgfSBlbHNlIGlmICh3b3JrZXJSZXN1bHQudHlwZSA9PT0gXCJza2lwXCIpIHtcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKFwiV29ya2VyIG5vdCBjcmVhdGVkLCBza2lwcGluZyBzdGF0aWMgYnVpbGRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHdvcmtlciA9IHdvcmtlclJlc3VsdC53b3JrZXI7XG4gICAgICAgICAgICAvLyBFbWl0IHdvcmtlciBzdGFydHVwIG1ldHJpYyBhZnRlciB3b3JrZXIgaXMgY3JlYXRlZFxuICAgICAgICAgICAgY29uc3Qgd29ya2VyU3RhcnR1cFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKSAtIHdvcmtlclN0YXJ0VGltZTtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy5vbk1ldHJpY3MpIHtcbiAgICAgICAgICAgICAgY29uc3Qgd29ya2VyU3RhcnR1cE1ldHJpYyA9IGNyZWF0ZVdvcmtlclN0YXJ0dXBNZXRyaWNzKHtcbiAgICAgICAgICAgICAgICByb3V0ZTogXCIvXCIsIC8vIFdvcmtlciBzdGFydHVwIGlzIGdsb2JhbCwgbm90IHJvdXRlLXNwZWNpZmljXG4gICAgICAgICAgICAgICAgd29ya2VyVHlwZTogXCJodG1sXCIsIC8vIFRoaXMgaXMgdGhlIEhUTUwgd29ya2VyIGZvciBzZXJ2ZXItc2lkZSBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgICAgIHN0YXJ0dXBUaW1lOiB3b3JrZXJTdGFydHVwVGltZSxcbiAgICAgICAgICAgICAgICBmcm9tTWFpblRocmVhZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBmcm9tUnNjV29ya2VyOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBmcm9tSHRtbFdvcmtlcjogZmFsc2UsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IGBIVE1MIHdvcmtlciBzdGFydHVwIGZvciBzZXJ2ZXItc2lkZSBzdGF0aWMgZ2VuZXJhdGlvbmAsXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAvLyBPbmx5IGVtaXQgbWV0cmljcyBmcm9tIHRoZSBzZXJ2ZXIgZW52aXJvbm1lbnQgdG8gcHJldmVudCBkdXBsaWNhdGVzXG4gICAgICAgICAgICAgIGlmICh0aGlzLmVudmlyb25tZW50Lm5hbWUgPT09IFwic2VydmVyXCIpIHtcbiAgICAgICAgICAgICAgICB1c2VyT3B0aW9ucy5vbk1ldHJpY3Mod29ya2VyU3RhcnR1cE1ldHJpYyk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFN0b3JlIHRoZSB3b3JrZXIgZ2xvYmFsbHkgdG8gcHJldmVudCBkdXBsaWNhdGUgY3JlYXRpb25cbiAgICAgICAgICAgIGdsb2JhbFdvcmtlciA9IHdvcmtlcjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBObyBSU0Mgd29ya2VyIG5lZWRlZCBmb3Igc3RhdGljIGdlbmVyYXRpb24gLSBtYWluIHRocmVhZCBydW5zIHdpdGggcmVhY3Qtc2VydmVyIGNvbmRpdGlvbnNcbiAgICAgICAgLy8gUmVuZGVyIHBhZ2VzIC0gY29tcG9uZW50IHJlc29sdXRpb24gbm93IGhhcHBlbnMgcGVyLXJvdXRlIGluIHJlbmRlclBhZ2VcbiAgICAgICAgY29uc3QgeyBvbkV2ZW50LCAuLi5oYW5kbGVyT3B0aW9ucyB9ID0gdXNlck9wdGlvbnM7XG5cbiAgICAgICAgLy8gRW1pdCB0aGUgc3RhdGljIHNpdGUgZ2VuZXJhdGlvbiBzdGFydCBldmVudFxuICAgICAgICBpZiAodHlwZW9mIHVzZXJPcHRpb25zLm9uRXZlbnQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByID0gdXNlck9wdGlvbnMub25FdmVudCh7XG4gICAgICAgICAgICAgIHR5cGU6IFwiYnVpbGQuc3NnLnN0YXJ0XCIsXG4gICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXAua2V5cygpID8/IFtdKSxcbiAgICAgICAgICAgICAgICBvcHRpb25zOiBudWxsIGFzIGFueSwgLy8gTm8gc3BlY2lmaWMgcm9sbHVwIG91dHB1dCBvcHRpb25zIGZvciBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgICAgIGJ1bmRsZTogYnVuZGxlLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAociAhPSBudWxsICYmIHR5cGVvZiByID09PSBcIm9iamVjdFwiICYmIFwidGhlblwiIGluIHIpIHtcbiAgICAgICAgICAgICAgYXdhaXQgKHIgYXMgUHJvbWlzZTxhbnk+KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgY29uc3QgZXZlbnRQYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICAgIHBhbmljVGhyZXNob2xkOiB1c2VyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgICAgICAgICAgY29udGV4dDogXCJvbkV2ZW50KGJ1aWxkLnNzZy5zdGFydClcIixcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGV2ZW50UGFuaWNFcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgICAgIHRocm93IGV2ZW50UGFuaWNFcnJvcjsgLy8gUmUtdGhyb3cgdG8gYWJvcnQgdGhlIGJ1aWxkXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJGYWlsZWQgdG8gZW1pdCBidWlsZC5zc2cuc3RhcnQgZXZlbnRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gU2VsZWN0IHJlbmRlciBtb2RlIGJhc2VkIG9uIGJ1aWxkIGNvbmZpZ1xuICAgICAgICBjb25zdCByZW5kZXJNb2RlID0gdXNlck9wdGlvbnMuYnVpbGQ/LnJlbmRlck1vZGUgPz8gXCJwYXJhbGxlbFwiO1xuICAgICAgICBjb25zdCByZW5kZXJQYWdlcyA9IHJlbmRlck1vZGUgPT09IFwic2VxdWVudGlhbFwiID8gcmVuZGVyUGFnZXNTZXF1ZW50aWFsIDogcmVuZGVyUGFnZXNCYXRjaGVkO1xuXG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oYFtzdGF0aWNdIFVzaW5nICR7cmVuZGVyTW9kZX0gcmVuZGVyaW5nJHtyZW5kZXJNb2RlID09PSBcInBhcmFsbGVsXCIgPyBgIChiYXRjaCBzaXplOiAke3VzZXJPcHRpb25zLmJ1aWxkPy5iYXRjaFNpemUgPz8gOH0pYCA6IFwiXCJ9YCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aGlzIHdpbGwgcmVuZGVyIHRoZSByb3V0ZXNcbiAgICAgICAgY29uc3QgcmVuZGVyUGFnZXNHZW5lcmF0b3IgPSByZW5kZXJQYWdlcyhcbiAgICAgICAgICByb3V0ZXMsXG4gICAgICAgICAge1xuICAgICAgICAgICAgLi4uaGFuZGxlck9wdGlvbnMsXG4gICAgICAgICAgICBsb2FkZXI6IGJ1aWxkTG9hZGVyLFxuICAgICAgICAgICAgd29ya2VyOiB3b3JrZXIsXG4gICAgICAgICAgICBodG1sV29ya2VyOiB3b3JrZXIsIC8vIFBhc3MgdGhlIEhUTUwgd29ya2VyIGZvciBIVE1MIGdlbmVyYXRpb25cbiAgICAgICAgICAgIGxvZ2dlcjogbG9nZ2VyLFxuICAgICAgICAgICAgLy8gUGFzcyBnbG9iYWwgQ1NTIHRvIGRvd25zdHJlYW0gcmVuZGVyZXJcbiAgICAgICAgICAgIGdsb2JhbENzcyxcbiAgICAgICAgICAgIC8vIFBhc3MgYWJvcnQgc2lnbmFsIHRvIGNhbmNlbCBvcGVyYXRpb25zIHdoZW4gZXJyb3JzIG9jY3VyXG4gICAgICAgICAgICBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoaGFuZGxlck9wdGlvbnMuaHRtbFRpbWVvdXQpLFxuICAgICAgICAgICAgb25FdmVudDogb25FdmVudCxcbiAgICAgICAgICAgIHNlcnZlclBpcGVhYmxlU3RyZWFtT3B0aW9uczogc2VydmVyUGlwZWFibGVTdHJlYW1PcHRpb25zLFxuICAgICAgICAgICAgY2xpZW50UGlwZWFibGVTdHJlYW1PcHRpb25zOiBjbGllbnRQaXBlYWJsZVN0cmVhbU9wdGlvbnMsXG4gICAgICAgICAgICBtYW5pZmVzdDogc2VydmVyTWFuaWZlc3QgPz8ge30sXG4gICAgICAgICAgICBzdGF0aWNNYW5pZmVzdDogc3RhdGljTWFuaWZlc3QsIC8vIFBhc3Mgc3RhdGljIG1hbmlmZXN0IGZvciBwYXRoIHJlc29sdXRpb25cbiAgICAgICAgICAgIGF1dG9EaXNjb3ZlcmVkRmlsZXM6IGF1dG9EaXNjb3ZlcmVkRmlsZXMhLFxuICAgICAgICAgICAgY3NzRmlsZXNCeVBhZ2U6IGNzc0ZpbGVzQnlQYWdlLFxuICAgICAgICAgICAgYmF0Y2hTaXplOiB1c2VyT3B0aW9ucy5idWlsZD8uYmF0Y2hTaXplLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgcmVuZGVyUGFnZVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIFByb2Nlc3MgcmVuZGVyIHJlc3VsdHNcbiAgICAgICAgbGV0IGZpbmFsUmVzdWx0OiBSZW5kZXJQYWdlc1Jlc3VsdCB8IHVuZGVmaW5lZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBmb3IgYXdhaXQgKGNvbnN0IHJlc3VsdCBvZiByZW5kZXJQYWdlc0dlbmVyYXRvcikge1xuICAgICAgICAgICAgLy8gSGFuZGxlIGVycm9yIHJlc3VsdHMgaW1tZWRpYXRlbHlcbiAgICAgICAgICAgIGlmIChyZXN1bHQudHlwZSA9PT0gXCJlcnJvclwiKSB7XG4gICAgICAgICAgICAgIHRocm93IHJlc3VsdC5lcnJvcjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSGFuZGxlIGZhaWxlZCByb3V0ZXMgYmFzZWQgb24gcGFuaWMgdGhyZXNob2xkXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIHJlc3VsdC50eXBlID09PSBcInN1Y2Nlc3NcIiAmJlxuICAgICAgICAgICAgICByZXN1bHQuZmFpbGVkUm91dGVzICYmXG4gICAgICAgICAgICAgIHJlc3VsdC5mYWlsZWRSb3V0ZXMuc2l6ZSA+IDBcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAvLyBVc2UgY2VudHJhbGl6ZWQgcGFuaWMgdGhyZXNob2xkIGxvZ2ljXG4gICAgICAgICAgICAgIGNvbnN0IGZpcnN0RXJyb3IgPSByZXN1bHQuZmFpbGVkUm91dGVzLnZhbHVlcygpLm5leHQoKS52YWx1ZTtcbiAgICAgICAgICAgICAgaWYgKGZpcnN0RXJyb3IgIT0gbnVsbCAmJiBzaG91bGRDYXVzZVBhbmljKGZpcnN0RXJyb3IsIHsgcGFuaWNUaHJlc2hvbGQ6IHVzZXJPcHRpb25zLnBhbmljVGhyZXNob2xkIH0pKSB7XG4gICAgICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgY2F1c2UgYSBwYW5pYywgdGhyb3cgdGhlIGVycm9yXG4gICAgICAgICAgICAgICAgdGhyb3cgZmlyc3RFcnJvcjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAvLyBGb3Igbm9uLXBhbmljIGVycm9ycywgbG9nIHdhcm5pbmdzIGJ1dCBjb250aW51ZVxuICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtyb3V0ZSwgZXJyb3JdIG9mIHJlc3VsdC5mYWlsZWRSb3V0ZXMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlcnIgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiB0b0Vycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICB0aGlzLndhcm4oXG4gICAgICAgICAgICAgICAgICBuZXcgRXJyb3IoXCJGYWlsZWQgdG8gcmVuZGVyIHJvdXRlOiBcIiArIHJvdXRlICsgXCJcXG5cIiArIGVyci5tZXNzYWdlICsgXCJcXG5cIiArIGVyci5zdGFjaywgeyBjYXVzZTogZXJyIH0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmaW5hbFJlc3VsdCA9IHJlc3VsdDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKHJlbmRlckVycm9yKSB7XG4gICAgICAgICAgLy8gSGFuZGxlIHJlbmRlciBlcnJvcnMgd2l0aCBwYW5pYyB0aHJlc2hvbGQgbG9naWNcbiAgICAgICAgICBjb25zdCByZW5kZXJQYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgICAgZXJyb3I6IHJlbmRlckVycm9yLFxuICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgICBjb250ZXh0OiBcInJlbmRlclBhZ2VzXCIsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHJlbmRlclBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgcmVuZGVyUGFuaWNFcnJvcjtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgcmVuZGVyRXJyb3I7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWZpbmFsUmVzdWx0KSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gcmVuZGVyIHJlc3VsdCBwcm9kdWNlZFwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBDYWxjdWxhdGUgZHVyYXRpb24gZnJvbSB0aW1pbmdcbiAgICAgICAgY29uc3QgZHVyYXRpb24gPSBNYXRoLnJvdW5kKFxuICAgICAgICAgIHBlcmZvcm1hbmNlLm5vdygpIC0gKHRpbWluZy5yZW5kZXJTdGFydCB8fCB0aW1pbmcuc3RhcnQpXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5pbmZvKFxuICAgICAgICAgIGBSZW5kZXJlZCAke2ZpbmFsUmVzdWx0LmNvbXBsZXRlZFJvdXRlcy5zaXplfSBwYWdlcyBpbiAke2R1cmF0aW9ufW1zYFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIEVtaXQgdGhlIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gY29tcGxldGlvbiBldmVudCBvbmNlXG4gICAgICAgIGlmICh0eXBlb2YgdXNlck9wdGlvbnMub25FdmVudCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHIgPSB1c2VyT3B0aW9ucy5vbkV2ZW50KHtcbiAgICAgICAgICAgICAgdHlwZTogXCJidWlsZC5zc2cuZW5kXCIsXG4gICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXAua2V5cygpID8/IFtdKSxcbiAgICAgICAgICAgICAgICBvcHRpb25zOiBudWxsIGFzIGFueSwgLy8gTm8gc3BlY2lmaWMgcm9sbHVwIG91dHB1dCBvcHRpb25zIGZvciBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgICAgIGJ1bmRsZTogYnVuZGxlLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAociAhPSBudWxsICYmIHR5cGVvZiByID09PSBcIm9iamVjdFwiICYmIFwidGhlblwiIGluIHIpIHtcbiAgICAgICAgICAgICAgYXdhaXQgKHIgYXMgUHJvbWlzZTxhbnk+KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgaWYgKGVycm9yICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7IC8vIFJlLXRocm93IHRvIGFib3J0IHRoZSBidWlsZFxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmFpbGVkIHRvIGVtaXQgYnVpbGQuc3NnLmVuZCBldmVudFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocHJvY2Vzcy5lbnZbXCJOT0RFX0VOVlwiXSAhPT0gXCJwcm9kdWN0aW9uXCIpIHtcbiAgICAgICAgICB0aGlzLndhcm4oXG4gICAgICAgICAgICBgVEhJUyBCVUlMRCBJUyBOT1QgSU5URU5ERUQgRk9SIFBST0RVQ1RJT04gKCR7cHJvY2Vzcy5lbnZbXCJOT0RFX0VOVlwiXX0pYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgdGltaW5nXG4gICAgICAgIHRpbWluZy5yZW5kZXIgPVxuICAgICAgICAgIHBlcmZvcm1hbmNlLm5vdygpIC0gKHRpbWluZy5yZW5kZXJTdGFydCA/PyB0aW1pbmcuc3RhcnQpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgY29udGV4dDogXCJ3cml0ZUJ1bmRsZVwiLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBMZXQgdGhlIGZpbmFsbHkgYmxvY2sgaGFuZGxlIGFkZGl0aW9uYWwgY2xlYW51cFxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgLy8gUmVzZXQgYW55IGNhY2hlZCBzdGF0ZSB0byBwcmV2ZW50IGlzc3VlcyBpbiBzdWJzZXF1ZW50IGJ1aWxkc1xuICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzID0gbnVsbDtcbiAgICAgICAgc2VydmVyTWFuaWZlc3QgPSB1bmRlZmluZWQ7XG4gICAgICAgIFxuICAgICAgICAvLyBDbGVhbiB1cCB3b3JrZXIgaWYgaXQgZXhpc3RzXG4gICAgICAgIGlmICh3b3JrZXIpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgd29ya2VyLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICAgICAgICAgICAgd29ya2VyLnRlcm1pbmF0ZSgpO1xuICAgICAgICAgIH0gY2F0Y2ggKHRlcm1pbmF0ZUVycm9yKSB7XG4gICAgICAgICAgICAvLyBJZ25vcmUgdGVybWluYXRpb24gZXJyb3JzXG4gICAgICAgICAgfVxuICAgICAgICAgIHdvcmtlciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAvLyBSZXNldCBnbG9iYWwgd29ya2VyIHNpbmNlIGl0J3MgYmVlbiB0ZXJtaW5hdGVkXG4gICAgICAgICAgZ2xvYmFsV29ya2VyID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChwYW5pY0Vycm9yICE9IG51bGwpIHtcbiAgICAgICAgLy8gRW5zdXJlIHdlIGhhdmUgYSBwcm9wZXIgRXJyb3Igb2JqZWN0IHRoYXQgY2FuIGhhdmUgcHJvcGVydGllcyBzZXQgb24gaXRcbiAgICAgICAgY29uc3QgZXJyb3JUb1Rocm93ID1cbiAgICAgICAgICBwYW5pY0Vycm9yIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICAgID8gcGFuaWNFcnJvclxuICAgICAgICAgICAgOiBuZXcgRXJyb3IoU3RyaW5nKHBhbmljRXJyb3IpKTtcblxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgRXJyb3Igb2JqZWN0IHRvIGF2b2lkIHRoZSBcImNvZGVcIiBwcm9wZXJ0eSBpc3N1ZVxuICAgICAgICBjb25zdCBmaW5hbEVycm9yID0gbmV3IEVycm9yKGVycm9yVG9UaHJvdy5tZXNzYWdlKTtcbiAgICAgICAgZmluYWxFcnJvci5zdGFjayA9IGVycm9yVG9UaHJvdy5zdGFjaztcbiAgICAgICAgZmluYWxFcnJvci5jYXVzZSA9IGVycm9yVG9UaHJvdy5jYXVzZTtcblxuICAgICAgICAvLyBDb3B5IGFueSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgdGhhdCBtaWdodCBiZSBuZWVkZWRcbiAgICAgICAgaWYgKGVycm9yVG9UaHJvdy5uYW1lKSBmaW5hbEVycm9yLm5hbWUgPSBlcnJvclRvVGhyb3cubmFtZTtcblxuICAgICAgICB0aHJvdyBmaW5hbEVycm9yO1xuICAgICAgfVxuICAgIH0sXG5cbiAgICBhc3luYyBjbG9zZUJ1bmRsZSgpIHtcbiAgICAgIC8vIENsZWFuIHVwIF92aXJ0dWFsIGZpbGVzIGFmdGVyIGJ1aWxkIGNvbXBsZXRlc1xuICAgICAgLy8gVGhlc2UgYXJlIFZpdGUncyBpbnRlcm5hbCB2aXJ0dWFsIG1vZHVsZXMgYW5kIGFyZW4ndCBuZWVkZWQgaW4gdGhlIGZpbmFsIG91dHB1dFxuICAgICAgaWYgKHRoaXMuZW52aXJvbm1lbnQubmFtZSA9PT0gXCJzZXJ2ZXJcIikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHsgZXhpc3RzU3luYyB9ID0gYXdhaXQgaW1wb3J0KFwibm9kZTpmc1wiKTtcbiAgICAgICAgICBjb25zdCB7IGpvaW4sIHJlc29sdmUgfSA9IGF3YWl0IGltcG9ydChcIm5vZGU6cGF0aFwiKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBVc2UgdGhlIHJlc29sdmVkIG91dHB1dCBkaXJlY3RvcnkgZnJvbSB0aGUgZW52aXJvbm1lbnQgY29uZmlnXG4gICAgICAgICAgY29uc3QgcmVzb2x2ZWRPdXREaXIgPSB0aGlzLmVudmlyb25tZW50LmNvbmZpZy5idWlsZD8ub3V0RGlyIFxuICAgICAgICAgICAgPyByZXNvbHZlKHRoaXMuZW52aXJvbm1lbnQuY29uZmlnLnJvb3QgfHwgdXNlck9wdGlvbnMucHJvamVjdFJvb3QsIHRoaXMuZW52aXJvbm1lbnQuY29uZmlnLmJ1aWxkLm91dERpcilcbiAgICAgICAgICAgIDogcmVzb2x2ZSh1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCwgdXNlck9wdGlvbnMuYnVpbGQub3V0RGlyKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBEb24ndCBjbGVhbiB1cCBzZXJ2ZXIvX3ZpcnR1YWwgLSB3ZSBuZWVkIGR5bmFtaWMtaW1wb3J0LWhlbHBlci5qcyBmb3IgcnVudGltZVxuICAgICAgICAgIC8vIE9ubHkgY2xlYW4gdXAgc3RhdGljL192aXJ0dWFsIGlmIGl0IGV4aXN0cyAoc2hvdWxkbid0LCBidXQganVzdCBpbiBjYXNlKVxuICAgICAgICAgIGNvbnN0IHN0YXRpY091dERpciA9IGpvaW4ocmVzb2x2ZWRPdXREaXIsIHVzZXJPcHRpb25zLmJ1aWxkLnN0YXRpYyB8fCBcInN0YXRpY1wiKTtcbiAgICAgICAgICBjb25zdCBzdGF0aWNWaXJ0dWFsRGlyID0gam9pbihzdGF0aWNPdXREaXIsIFwiX3ZpcnR1YWxcIik7XG4gICAgICAgICAgaWYgKGV4aXN0c1N5bmMoc3RhdGljVmlydHVhbERpcikpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgcm1TeW5jIH0gPSBhd2FpdCBpbXBvcnQoXCJub2RlOmZzXCIpO1xuICAgICAgICAgICAgcm1TeW5jKHN0YXRpY1ZpcnR1YWxEaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3BsdWdpbi5zZXJ2ZXJdIENsZWFuZWQgdXAgX3ZpcnR1YWwgZGlyZWN0b3J5OiAke3N0YXRpY1ZpcnR1YWxEaXJ9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIC8vIE5vbi1jcml0aWNhbCAtIGxvZyBidXQgZG9uJ3QgZmFpbCB0aGUgYnVpbGRcbiAgICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgbG9nZ2VyPy53YXJuKGBbcGx1Z2luLnNlcnZlcl0gRmFpbGVkIHRvIGNsZWFuIHVwIF92aXJ0dWFsIGRpcmVjdG9yeTogJHtlcnJvcn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gR3JhY2VmdWwgd29ya2VyIHNodXRkb3duIC0gb25seSBhdCB0aGUgZW5kIG9mIHRoZSBlbnRpcmUgYnVpbGQgcHJvY2Vzc1xuICAgICAgaWYgKHdvcmtlcikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgICAgICAgICBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICByZWplY3QobmV3IEVycm9yKFwiV29ya2VyIHNodXRkb3duIHRpbWVvdXRcIikpO1xuICAgICAgICAgICAgICB9LCB1c2VyT3B0aW9ucy53b3JrZXJTaHV0ZG93blRpbWVvdXQpO1xuXG4gICAgICAgICAgICAgIGNvbnN0IGJhY2t1cFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICByZWplY3QobmV3IEVycm9yKFwiV29ya2VyIHNodXRkb3duIGJhY2t1cCB0aW1lb3V0XCIpKTtcbiAgICAgICAgICAgICAgfSwgTWF0aC5mbG9vcih1c2VyT3B0aW9ucy53b3JrZXJTaHV0ZG93blRpbWVvdXQgKiAwLjYpKTsgLy8gNjAlIG9mIG1haW4gdGltZW91dFxuXG4gICAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2VIYW5kbGVyID0gKG1lc3NhZ2U6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChtZXNzYWdlLnR5cGUgPT09IFwiU0hVVERPV05fQ09NUExFVEVcIikge1xuICAgICAgICAgICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmluZm8oXCJXb3JrZXIgc2h1dGRvd24gY29tcGxldGVcIik7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQoYmFja3VwVGltZW91dCk7XG4gICAgICAgICAgICAgICAgICB3b3JrZXI/LnJlbW92ZUxpc3RlbmVyKFwibWVzc2FnZVwiLCBtZXNzYWdlSGFuZGxlcik7XG4gICAgICAgICAgICAgICAgICAvLyBSZW1vdmUgYWxsIG90aGVyIGV2ZW50IGxpc3RlbmVycyBhcyB3ZWxsXG4gICAgICAgICAgICAgICAgICB3b3JrZXI/LnJlbW92ZUFsbExpc3RlbmVycygpO1xuICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSBcIkNMRUFOVVBfQ09NUExFVEVcIikge1xuICAgICAgICAgICAgICAgICAgLy8gSGFuZGxlIGNsZWFudXAgY29tcGxldGUgbWVzc2FnZXMgZHVyaW5nIHNodXRkb3duIC0gdGhpcyBpcyBub3JtYWxcbiAgICAgICAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci5pbmZvKFwiV29ya2VyIGNsZWFudXAgY29tcGxldGVkIGR1cmluZyBzaHV0ZG93blwiKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIC8vIERvbid0IHJlc29sdmUgaGVyZSAtIHdhaXQgZm9yIFNIVVRET1dOX0NPTVBMRVRFXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgIFwiV29ya2VyIGlzIHN0aWxsIGJ1c3ksIHJlY2VpdmVkIG1lc3NhZ2UgXCIgKyBtZXNzYWdlPy50eXBlXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgIHdvcmtlcj8ub24oXCJtZXNzYWdlXCIsIG1lc3NhZ2VIYW5kbGVyKTtcblxuICAgICAgICAgICAgICAvLyBTZW5kIHNodXRkb3duIG1lc3NhZ2VcbiAgICAgICAgICAgICAgd29ya2VyPy5wb3N0TWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJTSFVURE9XTlwiLFxuICAgICAgICAgICAgICAgIGlkOiBcIipcIixcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICBdKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAvLyBJZiBzaHV0ZG93biBwcm90b2NvbCBmYWlscywgZm9yY2UgdGVybWluYXRlXG4gICAgICAgICAgdGhpcy53YXJuKFxuICAgICAgICAgICAgXCJXb3JrZXIgc2h1dGRvd24gcHJvdG9jb2wgZmFpbGVkLCBmb3JjaW5nIHRlcm1pbmF0aW9uOiBcIiArXG4gICAgICAgICAgICAgIChlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcikpXG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBEb24ndCB0cnkgdG8gY2xlYW4gdXAgbGlzdGVuZXJzIGluIGVycm9yIGNhc2UgLSBqdXN0IGZvcmNlIHRlcm1pbmF0ZVxuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIC8vIEFsd2F5cyBmb3JjZSBjbGVhbnVwIGFuZCB0ZXJtaW5hdGlvblxuICAgICAgICAgIGlmICh3b3JrZXIpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIHdvcmtlci5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICAgICAgICAgICAgd29ya2VyLnRlcm1pbmF0ZSgpO1xuICAgICAgICAgICAgfSBjYXRjaCAodGVybWluYXRlRXJyb3IpIHtcbiAgICAgICAgICAgICAgLy8gSWdub3JlIHRlcm1pbmF0aW9uIGVycm9yc1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd29ya2VyID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgLy8gUmVzZXQgZ2xvYmFsIHdvcmtlciBzaW5jZSBpdCdzIGJlZW4gdGVybWluYXRlZFxuICAgICAgICAgICAgZ2xvYmFsV29ya2VyID0gdW5kZWZpbmVkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gIH0gYXMgY29uc3Q7XG59O1xuIl0sIm5hbWVzIjpbInBhbmljRXJyb3IiLCJyZW5kZXJQYWdlcyIsInJlbmRlclBhZ2VzU2VxdWVudGlhbCIsImpvaW4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBMERBLGlCQUFrQixFQUFBO0FBY2xCLElBQUksWUFBQTtBQUVTLE1BQUEsaUJBQUEsR0FBa0MsU0FBUyxrQkFBQSxDQUN0RCxPQUNBLEVBQUE7QUFDQSxFQUFJLElBQUEsTUFBQTtBQUNKLEVBQUksSUFBQSxNQUFBO0FBQ0osRUFBSSxJQUFBLGNBQUE7QUFDSixFQUFBLElBQUksbUJBQWtELEdBQUEsSUFBQTtBQUN0RCxFQUFBLElBQUksY0FBdUMsR0FBQSxNQUFBO0FBQzNDLEVBQUksSUFBQSxTQUFBO0FBQ0osRUFBQSxNQUFNLE1BQXNCLEdBQUE7QUFBQSxJQUMxQixLQUFBLEVBQU8sWUFBWSxHQUFJLEVBQUE7QUFBQSxJQUN2QixjQUFnQixFQUFBLENBQUE7QUFBQSxJQUNoQixVQUFZLEVBQUEsQ0FBQTtBQUFBLElBQ1osV0FBYSxFQUFBO0FBQUEsR0FDZjtBQUVBLEVBQU0sTUFBQSxlQUFBLEdBQWtCLGVBQWUsT0FBTyxDQUFBO0FBQzlDLEVBQUksSUFBQSxlQUFBLENBQWdCLFNBQVMsT0FBUyxFQUFBO0FBQ3BDLElBQUEsTUFBTSxlQUFnQixDQUFBLEtBQUE7QUFBQTtBQUV4QixFQUFBLE1B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
|