vite-plugin-react-server 1.4.1 → 1.4.3

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.
Files changed (146) hide show
  1. package/README.md +48 -313
  2. package/dist/package.json +123 -13
  3. package/dist/plugin/bundle/deferredStaticGeneration.js +14 -39
  4. package/dist/plugin/bundle/manifests.js +30 -48
  5. package/dist/plugin/config/autoDiscover/resolveAutoDiscover.d.ts.map +1 -1
  6. package/dist/plugin/config/autoDiscover/resolveAutoDiscover.js +4 -1
  7. package/dist/plugin/config/envPrefixFromConfig.js +12 -7
  8. package/dist/plugin/config/getCondition.d.ts.map +1 -1
  9. package/dist/plugin/config/getCondition.js +7 -5
  10. package/dist/plugin/dev-server/configureReactServer.server.d.ts.map +1 -1
  11. package/dist/plugin/dev-server/configureReactServer.server.js +5 -8
  12. package/dist/plugin/dev-server/plugin.client.d.ts.map +1 -1
  13. package/dist/plugin/dev-server/plugin.client.js +2 -1
  14. package/dist/plugin/dev-server/plugin.server.d.ts.map +1 -1
  15. package/dist/plugin/dev-server/plugin.server.js +2 -36
  16. package/dist/plugin/dev-server/virtualRscHmrPlugin.js +23 -23
  17. package/dist/plugin/environments/createBuildEventPlugin.js +88 -98
  18. package/dist/plugin/environments/createEnvironmentPlugin.js +222 -250
  19. package/dist/plugin/error/index.d.ts +1 -2
  20. package/dist/plugin/error/index.d.ts.map +1 -1
  21. package/dist/plugin/error/index.js +2 -3
  22. package/dist/plugin/error/panicThresholdHandler.js +14 -3
  23. package/dist/plugin/error/setupGlobalErrorHandler.d.ts.map +1 -1
  24. package/dist/plugin/error/setupGlobalErrorHandler.js +23 -16
  25. package/dist/plugin/helpers/createRscRenderHelpers.d.ts +0 -5
  26. package/dist/plugin/helpers/createRscRenderHelpers.d.ts.map +1 -1
  27. package/dist/plugin/helpers/createRscRenderHelpers.js +32 -55
  28. package/dist/plugin/helpers/createSharedLoader.d.ts.map +1 -1
  29. package/dist/plugin/helpers/createSharedLoader.js +4 -2
  30. package/dist/plugin/helpers/headlessStreamReuseHandler.js +30 -22
  31. package/dist/plugin/helpers/headlessStreamState.d.ts +0 -38
  32. package/dist/plugin/helpers/headlessStreamState.d.ts.map +1 -1
  33. package/dist/plugin/helpers/headlessStreamState.js +15 -76
  34. package/dist/plugin/helpers/index.d.ts +0 -3
  35. package/dist/plugin/helpers/index.d.ts.map +1 -1
  36. package/dist/plugin/helpers/index.js +1 -4
  37. package/dist/plugin/helpers/requestInfo.d.ts.map +1 -1
  38. package/dist/plugin/helpers/requestInfo.js +3 -3
  39. package/dist/plugin/helpers/resolveComponent.d.ts.map +1 -1
  40. package/dist/plugin/helpers/resolveComponent.js +4 -2
  41. package/dist/plugin/helpers/workerCleanup.d.ts +1 -12
  42. package/dist/plugin/helpers/workerCleanup.d.ts.map +1 -1
  43. package/dist/plugin/helpers/workerCleanup.js +1 -1
  44. package/dist/plugin/index.client.d.ts +5 -0
  45. package/dist/plugin/index.client.d.ts.map +1 -0
  46. package/dist/plugin/index.client.js +4 -0
  47. package/dist/plugin/index.d.ts +4 -3
  48. package/dist/plugin/index.d.ts.map +1 -1
  49. package/dist/plugin/index.js +10 -5
  50. package/dist/plugin/index.server.d.ts +5 -0
  51. package/dist/plugin/index.server.d.ts.map +1 -0
  52. package/dist/plugin/index.server.js +4 -0
  53. package/dist/plugin/loader/directives/index.d.ts +0 -1
  54. package/dist/plugin/loader/directives/index.d.ts.map +1 -1
  55. package/dist/plugin/loader/directives/index.js +1 -2
  56. package/dist/plugin/metrics/createWorkerStartupMetrics.js +31 -13
  57. package/dist/plugin/orchestrator/createPluginOrchestrator.client.js +41 -38
  58. package/dist/plugin/orchestrator/createPluginOrchestrator.server.js +43 -46
  59. package/dist/plugin/plugin.client.js +2 -2
  60. package/dist/plugin/plugin.server.js +2 -2
  61. package/dist/plugin/react-static/createBuildLoader.client.js +12 -6
  62. package/dist/plugin/react-static/createBuildLoader.server.js +255 -235
  63. package/dist/plugin/react-static/plugin.client.js +684 -770
  64. package/dist/plugin/react-static/plugin.server.js +517 -603
  65. package/dist/plugin/react-static/processCssFilesForPages.js +103 -88
  66. package/dist/plugin/react-static/renderPage.client.js +455 -529
  67. package/dist/plugin/react-static/renderPage.server.js +485 -508
  68. package/dist/plugin/react-static/renderPagesBatched.js +277 -275
  69. package/dist/plugin/react-static/rscToHtmlStream.client.js +48 -29
  70. package/dist/plugin/react-static/rscToHtmlStream.server.js +62 -37
  71. package/dist/plugin/react-static/temporaryReferences.server.js +11 -2
  72. package/dist/plugin/stream/createMainThreadHandlers.js +40 -31
  73. package/dist/plugin/stream/renderRscStream.server.d.ts.map +1 -1
  74. package/dist/plugin/stream/renderRscStream.server.js +127 -144
  75. package/dist/plugin/transformer/createTransformerPlugin.js +226 -265
  76. package/dist/plugin/utils/checkReactVersion.d.ts +7 -0
  77. package/dist/plugin/utils/checkReactVersion.d.ts.map +1 -0
  78. package/dist/plugin/utils/checkReactVersion.js +23 -0
  79. package/dist/plugin/utils/envUrls.node.js +12 -11
  80. package/dist/plugin/vendor/vendor-alias.js +84 -114
  81. package/dist/plugin/vendor/vendor.client.d.ts.map +1 -1
  82. package/dist/plugin/vendor/vendor.client.js +1 -3
  83. package/dist/plugin/worker/rsc/handleRscRender.d.ts.map +1 -1
  84. package/dist/plugin/worker/rsc/handleRscRender.js +3 -1
  85. package/dist/tsconfig.tsbuildinfo +1 -1
  86. package/package.json +123 -13
  87. package/plugin/config/autoDiscover/resolveAutoDiscover.ts +4 -0
  88. package/plugin/config/getCondition.ts +6 -4
  89. package/plugin/dev-server/configureReactServer.server.ts +7 -10
  90. package/plugin/dev-server/plugin.client.ts +2 -0
  91. package/plugin/dev-server/plugin.server.ts +2 -49
  92. package/plugin/error/index.ts +1 -2
  93. package/plugin/error/setupGlobalErrorHandler.ts +24 -25
  94. package/plugin/helpers/createRscRenderHelpers.ts +0 -29
  95. package/plugin/helpers/createSharedLoader.ts +6 -1
  96. package/plugin/helpers/headlessStreamState.ts +0 -69
  97. package/plugin/helpers/index.ts +0 -3
  98. package/plugin/helpers/requestInfo.ts +1 -2
  99. package/plugin/helpers/resolveComponent.ts +6 -1
  100. package/plugin/helpers/workerCleanup.ts +1 -38
  101. package/plugin/index.client.ts +4 -0
  102. package/plugin/index.server.ts +4 -0
  103. package/plugin/index.ts +12 -5
  104. package/plugin/loader/directives/index.ts +0 -1
  105. package/plugin/plugin.client.ts +1 -1
  106. package/plugin/plugin.server.ts +1 -1
  107. package/plugin/stream/renderRscStream.server.ts +3 -0
  108. package/plugin/transformer/README.md +1 -1
  109. package/plugin/utils/checkReactVersion.ts +28 -0
  110. package/plugin/vendor/vendor.client.ts +0 -2
  111. package/plugin/worker/html/README.md +1 -1
  112. package/plugin/worker/rsc/README.md +1 -1
  113. package/plugin/worker/rsc/handleRscRender.ts +2 -0
  114. package/scripts/generate-toc.mjs +27 -294
  115. package/dist/plugin/error/assertPanic.d.ts +0 -2
  116. package/dist/plugin/error/assertPanic.d.ts.map +0 -1
  117. package/dist/plugin/error/assertPanic.js +0 -15
  118. package/dist/plugin/error/directiveError.d.ts +0 -13
  119. package/dist/plugin/error/directiveError.d.ts.map +0 -1
  120. package/dist/plugin/error/directiveError.js +0 -21
  121. package/dist/plugin/error/enhanceError.d.ts +0 -14
  122. package/dist/plugin/error/enhanceError.d.ts.map +0 -1
  123. package/dist/plugin/error/enhanceError.js +0 -24
  124. package/dist/plugin/helpers/createSafePageComponent.d.ts +0 -36
  125. package/dist/plugin/helpers/createSafePageComponent.d.ts.map +0 -1
  126. package/dist/plugin/helpers/createSafePageComponent.js +0 -50
  127. package/dist/plugin/helpers/moduleResolver.d.ts +0 -25
  128. package/dist/plugin/helpers/moduleResolver.d.ts.map +0 -1
  129. package/dist/plugin/helpers/moduleResolver.js +0 -64
  130. package/dist/plugin/helpers/stashReturnValue.d.ts +0 -3
  131. package/dist/plugin/helpers/stashReturnValue.d.ts.map +0 -1
  132. package/dist/plugin/helpers/stashReturnValue.js +0 -23
  133. package/dist/plugin/helpers/workerManager.d.ts +0 -5
  134. package/dist/plugin/helpers/workerManager.d.ts.map +0 -1
  135. package/dist/plugin/helpers/workerManager.js +0 -18
  136. package/dist/plugin/loader/directives/collectExportsFromModule.d.ts +0 -6
  137. package/dist/plugin/loader/directives/collectExportsFromModule.d.ts.map +0 -1
  138. package/dist/plugin/loader/directives/collectExportsFromModule.js +0 -24
  139. package/plugin/error/assertPanic.ts +0 -9
  140. package/plugin/error/directiveError.ts +0 -29
  141. package/plugin/error/enhanceError.ts +0 -41
  142. package/plugin/helpers/createSafePageComponent.ts +0 -64
  143. package/plugin/helpers/moduleResolver.ts +0 -91
  144. package/plugin/helpers/stashReturnValue.ts +0 -19
  145. package/plugin/helpers/workerManager.ts +0 -16
  146. package/plugin/loader/directives/collectExportsFromModule.ts +0 -25
@@ -1,623 +1,537 @@
1
1
  /**
2
- * plugin.ts
3
- *
4
- * PURPOSE: Main Vite plugin for React Server Components (RSC) static site generation
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, } from "vite";
17
- import { resolveOptions } from "../config/resolveOptions.js";
18
- import { createBuildLoader } from "./createBuildLoader.server.js";
19
- import { renderPagesBatched } from "./renderPagesBatched.js";
20
- import { renderPages as renderPagesSequential } from "./renderPages.js";
21
- import { getBundleManifest } from "../helpers/getBundleManifest.js";
22
- import { createWorker } from "../worker/createWorker.js";
23
- import { serializedOptions, serializeResolvedConfig, } from "../helpers/serializeUserOptions.js";
24
- import { performance } from "node:perf_hooks";
25
- import { baseURL } from "../utils/envUrls.node.js";
26
- import { handleError } from "../error/handleError.js";
27
- import { shouldCausePanic } from "../error/panicThresholdHandler.js";
28
- import { renderPage } from "./renderPage.server.js";
29
- import { temporaryReferences } from "./temporaryReferences.server.js";
30
- import { configurePreviewServer } from "./configurePreviewServer.js";
31
- import { envPrefixFromConfig } from "../config/envPrefixFromConfig.js";
32
- import { processCssFilesForPages } from "./processCssFilesForPages.js";
33
- import { createWorkerStartupMetrics } from "../metrics/createWorkerStartupMetrics.js";
34
- import { tryManifest } from "../helpers/tryManifest.js";
35
- import { join } from "node:path";
36
- import { resolveAutoDiscover } from "../config/autoDiscover/resolveAutoDiscover.js";
37
- import { assertReactServer } from "../config/getCondition.js";
38
- import { toError } from "../error/toError.js";
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
- export const reactStaticPlugin = function _reactStaticPlugin(options) {
54
- let worker;
55
- let logger;
56
- let resolvedConfig;
57
- let autoDiscoveredFiles = null;
58
- let serverManifest = undefined;
59
- let configEnv;
60
- const timing = {
61
- start: performance.now(),
62
- configResolved: 0,
63
- buildStart: 0,
64
- renderStart: 0,
65
- };
66
- const resolvedOptions = resolveOptions(options);
67
- if (resolvedOptions.type === "error") {
68
- throw resolvedOptions.error;
69
- }
70
- const userOptions = resolvedOptions.userOptions;
71
- return {
72
- name: "vite:plugin-react-server/server-static",
73
- enforce: "post",
74
- api: {
75
- meta: { timing },
76
- },
77
- async config(_config, viteConfigEnv) {
78
- configEnv = viteConfigEnv;
79
- },
80
- applyToEnvironment(partialEnvironment) {
81
- if (["server"].includes(partialEnvironment.name)) {
82
- return true;
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
- return false;
85
- },
86
- async configResolved(config) {
87
- resolvedConfig = config;
88
- if (!logger) {
89
- logger = config.customLogger ?? createLogger();
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
- const autoDiscoverResult = await resolveAutoDiscover({
92
- config: config,
93
- configEnv: configEnv,
94
- userOptions,
95
- logger,
96
- });
97
- if (autoDiscoverResult.type === "error") {
98
- throw autoDiscoverResult.error;
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
- autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
101
- },
102
- async buildStart() {
103
- if (!logger) {
104
- logger = this.environment.logger;
270
+ });
271
+ if (workerResult.type === "error") {
272
+ if (workerResult.error != null) {
273
+ throw workerResult.error;
105
274
  }
106
- timing.buildStart = performance.now();
107
- if (userOptions.onEvent && autoDiscoveredFiles) {
108
- try {
109
- userOptions.onEvent({
110
- type: "build.start",
111
- data: {
112
- pages: Array.from(autoDiscoveredFiles.urlMap.keys()),
113
- files: autoDiscoveredFiles,
114
- },
115
- });
116
- }
117
- catch (error) {
118
- const panicError = handleError({
119
- error,
120
- logger: logger,
121
- panicThreshold: userOptions.panicThreshold,
122
- context: "buildStart",
123
- });
124
- if (panicError != null) {
125
- worker?.terminate();
126
- throw panicError;
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
- // the preview server helps to view the generated static folder, but only when the static plugin is enabled
135
- // if no build.pages, then the preview server will instead use default vite preview server
136
- // it works the same under both conditions
137
- async configurePreviewServer(server) {
138
- logger = server.config.customLogger || server.config.logger;
139
- configurePreviewServer({
140
- server,
141
- userOptions,
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
- async renderStart() {
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
- let panicError = null;
186
- let bundleManifest = undefined;
187
- if (!logger) {
188
- logger = this.environment.logger;
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
- // handle the bundle manifest
191
- try {
192
- bundleManifest = getBundleManifest({
193
- bundle,
194
- normalizer: userOptions.normalizer,
195
- });
196
- // make sure that we have a manifest
197
- const manifestPath = typeof resolvedConfig.build.manifest === "string"
198
- ? resolvedConfig.build.manifest
199
- : ".vite/manifest.json";
200
- if (!bundleManifest[manifestPath] ||
201
- !("source" in bundleManifest[manifestPath])) {
202
- throw new Error("Server manifest not found");
203
- }
204
- // parse the manifest
205
- serverManifest = JSON.parse(bundleManifest[manifestPath].source);
206
- // make sure that we have a manifest
207
- if (!serverManifest) {
208
- throw new Error("Failed to parse server manifest");
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
- catch (error) {
212
- const panicError = handleError({
213
- error,
214
- logger: logger,
215
- panicThreshold: userOptions.panicThreshold,
216
- context: "writeBundle(bundleManifest)",
217
- });
218
- if (panicError != null) {
219
- throw panicError;
220
- }
221
- else {
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
- try {
226
- const staticManifestResult = await tryManifest({
227
- root: userOptions.projectRoot,
228
- outDir: join(userOptions.build.outDir, userOptions.build.static),
229
- manifestPath: resolvedConfig.build.manifest,
230
- ssrManifest: false,
231
- });
232
- if (staticManifestResult.type === "error") {
233
- throw staticManifestResult.error;
234
- }
235
- const staticManifest = staticManifestResult.manifest;
236
- // Don't create helper file - let resolveVirtualAndNodeModules shim handle it
237
- // Same approach as client environment - no special file needed
238
- const buildLoader = createBuildLoader({
239
- userOptions: userOptions,
240
- serverManifest: serverManifest ?? {},
241
- staticManifest: staticManifest,
242
- }, bundle, temporaryReferences, logger);
243
- // Create CSS props for each CSS file
244
- const { cssFilesByPage, globalCss } = processCssFilesForPages({
245
- userOptions,
246
- autoDiscoveredFiles,
247
- serverManifest,
248
- staticManifest,
249
- bundle,
250
- logger,
251
- });
252
- if (userOptions.verbose) {
253
- logger.info(`[plugin.server] cssFilesByPage size: ${cssFilesByPage.size}`);
254
- for (const [route, cssMap] of cssFilesByPage.entries()) {
255
- logger.info(`[plugin.server] Route ${route}: ${cssMap.size} CSS files`);
256
- }
257
- }
258
- const indexHtml = staticManifest?.["index.html"]?.file;
259
- const serverPipeableStreamOptions = {
260
- ...userOptions.serverPipeableStreamOptions,
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
- if (panicError != null) {
510
- // Ensure we have a proper Error object that can have properties set on it
511
- const errorToThrow = panicError instanceof Error
512
- ? panicError
513
- : new Error(String(panicError));
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
- async closeBundle() {
525
- // Clean up _virtual files after build completes
526
- // These are Vite's internal virtual modules and aren't needed in the final output
527
- if (this.environment.name === "server") {
528
- try {
529
- const { existsSync } = await import("node:fs");
530
- const { join, resolve } = await import("node:path");
531
- // Use the resolved output directory from the environment config
532
- const resolvedOutDir = this.environment.config.build?.outDir
533
- ? resolve(this.environment.config.root || userOptions.projectRoot, this.environment.config.build.outDir)
534
- : resolve(userOptions.projectRoot, userOptions.build.outDir);
535
- // Don't clean up server/_virtual - we need dynamic-import-helper.js for runtime
536
- // Only clean up static/_virtual if it exists (shouldn't, but just in case)
537
- const staticOutDir = join(resolvedOutDir, userOptions.build.static || "static");
538
- const staticVirtualDir = join(staticOutDir, "_virtual");
539
- if (existsSync(staticVirtualDir)) {
540
- const { rmSync } = await import("node:fs");
541
- rmSync(staticVirtualDir, { recursive: true, force: true });
542
- if (userOptions.verbose) {
543
- logger?.info(`[plugin.server] Cleaned up _virtual directory: ${staticVirtualDir}`);
544
- }
545
- }
546
- }
547
- catch (error) {
548
- // Non-critical - log but don't fail the build
549
- if (userOptions.verbose) {
550
- logger?.warn(`[plugin.server] Failed to clean up _virtual directory: ${error}`);
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
- // Graceful worker shutdown - only at the end of the entire build process
555
- if (worker) {
556
- try {
557
- await Promise.race([
558
- new Promise((resolve, reject) => {
559
- const timeout = setTimeout(() => {
560
- reject(new Error("Worker shutdown timeout"));
561
- }, userOptions.workerShutdownTimeout);
562
- const backupTimeout = setTimeout(() => {
563
- reject(new Error("Worker shutdown backup timeout"));
564
- }, Math.floor(userOptions.workerShutdownTimeout * 0.6)); // 60% of main timeout
565
- const messageHandler = (message) => {
566
- if (message.type === "SHUTDOWN_COMPLETE") {
567
- if (userOptions.verbose) {
568
- logger.info("Worker shutdown complete");
569
- }
570
- clearTimeout(timeout);
571
- clearTimeout(backupTimeout);
572
- worker?.removeListener("message", messageHandler);
573
- // Remove all other event listeners as well
574
- worker?.removeAllListeners();
575
- resolve();
576
- }
577
- else if (message.type === "CLEANUP_COMPLETE") {
578
- // Handle cleanup complete messages during shutdown - this is normal
579
- if (userOptions.verbose) {
580
- logger.info("Worker cleanup completed during shutdown");
581
- }
582
- // Don't resolve here - wait for SHUTDOWN_COMPLETE
583
- }
584
- else {
585
- if (userOptions.verbose) {
586
- logger.info("Worker is still busy, received message " + message?.type);
587
- }
588
- }
589
- };
590
- worker?.on("message", messageHandler);
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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