vite-plugin-react-server 1.4.2 → 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.
- 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/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,801 +1,715 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* plugin
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* This module:
|
|
7
|
-
* 1. Handles static site generation in the client environment
|
|
8
|
-
* 2. Uses RSC worker for RSC rendering and main-thread for HTML rendering
|
|
9
|
-
* 3. Generates both RSC and HTML files for static pages
|
|
10
|
-
* 4. Integrates with Vite's build process
|
|
11
|
-
*
|
|
12
|
-
* Feature parity with main react-static plugin, but in reverse. Uses rsc-worker to render rsc, and main thread for html.
|
|
13
|
-
* This is not the default behavior, but is supported for testing and custom app development purposes.
|
|
14
|
-
* Additionally, this can make it easier to use the --app flag to build all the modules + static generation at once.
|
|
2
|
+
* vite-plugin-react-server
|
|
3
|
+
* Copyright (c) Nico Brinkkemper
|
|
4
|
+
* MIT License
|
|
15
5
|
*/
|
|
16
|
-
import { createLogger
|
|
17
|
-
import { resolveOptions } from
|
|
18
|
-
import { renderPagesBatched } from
|
|
19
|
-
import { performance } from
|
|
20
|
-
import { renderPage } from
|
|
21
|
-
import { createWorker } from
|
|
22
|
-
import {
|
|
23
|
-
import { getBundleManifest } from
|
|
24
|
-
import { handleError } from
|
|
25
|
-
import { shouldCausePanic } from
|
|
26
|
-
import { configurePreviewServer } from
|
|
27
|
-
import { assertNonReactServer } from
|
|
28
|
-
import { envPrefixFromConfig } from
|
|
29
|
-
import { createWorkerStartupMetrics } from
|
|
30
|
-
import { processCssFilesForPages } from
|
|
31
|
-
import { createBuildLoader } from
|
|
32
|
-
import { getNodeEnv } from
|
|
33
|
-
import { toError } from
|
|
34
|
-
import { addStaticManifest, manifests, getSharedManifestStore
|
|
35
|
-
import { deferStaticGeneration } from
|
|
36
|
-
import { resolveAutoDiscover } from
|
|
37
|
-
import { join } from
|
|
38
|
-
import { baseURL } from
|
|
39
|
-
import { tryManifest } from
|
|
40
|
-
|
|
6
|
+
import { createLogger } from 'vite';
|
|
7
|
+
import { resolveOptions } from '../config/resolveOptions.js';
|
|
8
|
+
import { renderPagesBatched } from './renderPagesBatched.js';
|
|
9
|
+
import { performance } from 'node:perf_hooks';
|
|
10
|
+
import { renderPage } from './renderPage.client.js';
|
|
11
|
+
import { createWorker } from '../worker/createWorker.js';
|
|
12
|
+
import { serializeResolvedConfig, serializedOptions } from '../helpers/serializeUserOptions.js';
|
|
13
|
+
import { getBundleManifest } from '../helpers/getBundleManifest.js';
|
|
14
|
+
import { handleError } from '../error/handleError.js';
|
|
15
|
+
import { shouldCausePanic } from '../error/panicThresholdHandler.js';
|
|
16
|
+
import { configurePreviewServer } from './configurePreviewServer.js';
|
|
17
|
+
import { assertNonReactServer } from '../config/getCondition.js';
|
|
18
|
+
import { envPrefixFromConfig } from '../config/envPrefixFromConfig.js';
|
|
19
|
+
import { createWorkerStartupMetrics } from '../metrics/createWorkerStartupMetrics.js';
|
|
20
|
+
import { processCssFilesForPages } from './processCssFilesForPages.js';
|
|
21
|
+
import { createBuildLoader } from './createBuildLoader.client.js';
|
|
22
|
+
import { getNodeEnv } from '../config/getNodeEnv.js';
|
|
23
|
+
import { toError } from '../error/toError.js';
|
|
24
|
+
import { addStaticManifest, manifests, getSharedManifestStore } from '../bundle/manifests.js';
|
|
25
|
+
import { deferStaticGeneration } from '../bundle/deferredStaticGeneration.js';
|
|
26
|
+
import { resolveAutoDiscover } from '../config/autoDiscover/resolveAutoDiscover.js';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
import { baseURL } from '../utils/envUrls.node.js';
|
|
29
|
+
import { tryManifest } from '../helpers/tryManifest.js';
|
|
30
|
+
|
|
41
31
|
assertNonReactServer();
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
32
|
+
const reactStaticPlugin = function _reactStaticPlugin(options) {
|
|
33
|
+
let logger;
|
|
34
|
+
let autoDiscoveredFiles = null;
|
|
35
|
+
let rscWorker = void 0;
|
|
36
|
+
let resolvedConfig = null;
|
|
37
|
+
let serverManifest = void 0;
|
|
38
|
+
let staticBundle = void 0;
|
|
39
|
+
let serverBundle = void 0;
|
|
40
|
+
let configEnv;
|
|
41
|
+
const timing = {
|
|
42
|
+
start: performance.now(),
|
|
43
|
+
configResolved: 0,
|
|
44
|
+
buildStart: 0,
|
|
45
|
+
renderStart: 0
|
|
46
|
+
};
|
|
47
|
+
const resolvedOptions = resolveOptions(options);
|
|
48
|
+
if (resolvedOptions.type === "error") {
|
|
49
|
+
throw resolvedOptions.error;
|
|
50
|
+
}
|
|
51
|
+
const userOptions = resolvedOptions.userOptions;
|
|
52
|
+
return {
|
|
53
|
+
name: "vite:plugin-react-server/client-static",
|
|
54
|
+
enforce: "post",
|
|
55
|
+
apply: "build",
|
|
56
|
+
// Apply to build mode
|
|
57
|
+
api: {
|
|
58
|
+
meta: { timing }
|
|
59
|
+
},
|
|
60
|
+
async config(_config, viteConfigEnv) {
|
|
61
|
+
configEnv = viteConfigEnv;
|
|
62
|
+
},
|
|
63
|
+
applyToEnvironment(partialEnvironment) {
|
|
64
|
+
const envName = partialEnvironment.name;
|
|
65
|
+
if (["static", "client"].includes(envName)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
},
|
|
70
|
+
async configResolved(config) {
|
|
71
|
+
timing.configResolved = performance.now();
|
|
72
|
+
logger = config.customLogger || createLogger();
|
|
73
|
+
resolvedConfig = config;
|
|
74
|
+
const autoDiscoverResult = await resolveAutoDiscover({
|
|
75
|
+
config,
|
|
76
|
+
configEnv: configEnv || {
|
|
77
|
+
mode: config.mode,
|
|
78
|
+
command: config.command},
|
|
79
|
+
userOptions,
|
|
80
|
+
logger
|
|
81
|
+
});
|
|
82
|
+
if (autoDiscoverResult.type === "error") {
|
|
83
|
+
throw autoDiscoverResult.error;
|
|
84
|
+
}
|
|
85
|
+
autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
|
|
86
|
+
if (userOptions.verbose) {
|
|
87
|
+
logger?.info(`Auto-discovery ${autoDiscoverResult.type === "success" ? "completed" : "skipped"}`);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
async buildStart() {
|
|
91
|
+
timing.buildStart = performance.now();
|
|
92
|
+
if (userOptions.verbose) {
|
|
93
|
+
logger?.info("[react-static-client] Build started");
|
|
94
|
+
}
|
|
95
|
+
if (userOptions.onEvent && autoDiscoveredFiles) {
|
|
96
|
+
try {
|
|
97
|
+
userOptions.onEvent({
|
|
98
|
+
type: "build.start",
|
|
99
|
+
data: {
|
|
100
|
+
pages: Array.from(autoDiscoveredFiles.urlMap.keys()),
|
|
101
|
+
files: autoDiscoveredFiles
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
const panicError = handleError({
|
|
106
|
+
error,
|
|
107
|
+
logger,
|
|
108
|
+
panicThreshold: userOptions.panicThreshold});
|
|
109
|
+
if (panicError != null) {
|
|
110
|
+
rscWorker?.terminate();
|
|
111
|
+
throw panicError;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
async renderStart() {
|
|
117
|
+
timing.renderStart = performance.now();
|
|
118
|
+
if (userOptions.verbose) {
|
|
119
|
+
logger?.info("[react-static-client] Render started");
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
// the preview server helps to view the generated static folder, but only when the static plugin is enabled
|
|
123
|
+
// if no build.pages, then the preview server will instead use default vite preview server
|
|
124
|
+
// it works the same under both conditions
|
|
125
|
+
async configurePreviewServer(server) {
|
|
126
|
+
logger = server.config.customLogger || server.config.logger;
|
|
127
|
+
configurePreviewServer({
|
|
128
|
+
server,
|
|
129
|
+
userOptions
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
async writeBundle(_options, bundle) {
|
|
133
|
+
try {
|
|
134
|
+
if (!autoDiscoveredFiles?.urlMap) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const bundleManifest = getBundleManifest({
|
|
138
|
+
bundle,
|
|
139
|
+
normalizer: userOptions.normalizer
|
|
140
|
+
});
|
|
141
|
+
if (this.environment.name === "static") {
|
|
142
|
+
addStaticManifest(bundleManifest);
|
|
143
|
+
staticBundle = bundle;
|
|
144
|
+
} else if (this.environment.name === "client") {
|
|
145
|
+
if (manifests.static) {
|
|
146
|
+
const staticManifest = manifests.static;
|
|
147
|
+
for (const [, chunk] of Object.entries(bundle)) {
|
|
148
|
+
if (chunk.type === "chunk" && chunk.fileName) {
|
|
149
|
+
const normalized = userOptions.normalizer(chunk.fileName);
|
|
150
|
+
let value = normalized[1];
|
|
151
|
+
if (value.startsWith(userOptions.moduleBasePath)) {
|
|
152
|
+
value = value.slice(userOptions.moduleBasePath.length);
|
|
153
|
+
}
|
|
154
|
+
const entry = staticManifest[value];
|
|
155
|
+
if (entry && entry.file !== chunk.fileName) {
|
|
156
|
+
chunk.fileName = entry.file;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
93
159
|
}
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
160
|
+
}
|
|
161
|
+
} else if (this.environment.name === "server") {
|
|
162
|
+
serverBundle = bundle;
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
const panicError = handleError({
|
|
167
|
+
error,
|
|
168
|
+
logger,
|
|
169
|
+
panicThreshold: userOptions.panicThreshold});
|
|
170
|
+
if (panicError != null) {
|
|
171
|
+
throw panicError;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
async closeBundle() {
|
|
176
|
+
const envName = this.environment.name;
|
|
177
|
+
const isSsr = this.environment.config.build?.ssr === true;
|
|
178
|
+
if (userOptions.verbose) {
|
|
179
|
+
logger?.info(`[react-static-client] closeBundle called for environment: ${envName}, ssr: ${isSsr}`);
|
|
180
|
+
}
|
|
181
|
+
if (envName === "ssr" || envName === "server" || isSsr) {
|
|
182
|
+
if (userOptions.verbose) {
|
|
183
|
+
logger?.info(`[react-static-client] Skipping static generation for environment: ${envName} (ssr: ${isSsr})`);
|
|
184
|
+
}
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (envName === "static" || envName === "client" && !isSsr) {
|
|
188
|
+
try {
|
|
189
|
+
const { rmSync, existsSync } = await import('node:fs');
|
|
190
|
+
const { join: join2, resolve } = await import('node:path');
|
|
191
|
+
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);
|
|
192
|
+
const outputDirs = [
|
|
193
|
+
join2(resolvedOutDir, userOptions.build.static || "static"),
|
|
194
|
+
join2(resolvedOutDir, userOptions.build.client || "client")
|
|
195
|
+
];
|
|
196
|
+
for (const outDir of outputDirs) {
|
|
197
|
+
const virtualDir = join2(outDir, "_virtual");
|
|
198
|
+
if (existsSync(virtualDir)) {
|
|
199
|
+
rmSync(virtualDir, { recursive: true, force: true });
|
|
200
|
+
if (userOptions.verbose) {
|
|
201
|
+
logger?.info(`[react-static-client] Cleaned up _virtual directory: ${virtualDir}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (userOptions.verbose) {
|
|
207
|
+
logger?.warn(`[react-static-client] Failed to clean up _virtual directory: ${error}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (envName === "ssr" || envName === "server" || isSsr) {
|
|
212
|
+
if (userOptions.verbose) {
|
|
213
|
+
logger?.info(`[react-static-client] Skipping static generation - not in static environment (${envName}, ssr: ${isSsr})`);
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const closeBundleContext = this;
|
|
218
|
+
deferStaticGeneration(async () => {
|
|
219
|
+
try {
|
|
220
|
+
if (!autoDiscoveredFiles) {
|
|
221
|
+
if (userOptions.verbose) {
|
|
222
|
+
logger?.warn("[react-static-client] autoDiscoveredFiles not set, attempting to re-discover");
|
|
223
|
+
}
|
|
224
|
+
const { getStashedUserOptions, getEnvironmentId } = await import('../config/stashedOptionsState.js');
|
|
225
|
+
const { getCondition } = await import('../config/getCondition.js');
|
|
226
|
+
const envId = getEnvironmentId(getCondition(), resolvedConfig?.mode || "production");
|
|
227
|
+
const stashedOptions = getStashedUserOptions(envId);
|
|
228
|
+
if (stashedOptions && resolvedConfig) {
|
|
229
|
+
const autoDiscoverResult = await resolveAutoDiscover({
|
|
230
|
+
config: resolvedConfig,
|
|
103
231
|
configEnv: configEnv || {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
232
|
+
mode: resolvedConfig.mode || "production",
|
|
233
|
+
command: resolvedConfig.command || "build",
|
|
234
|
+
isSsrBuild: false,
|
|
235
|
+
isPreview: false
|
|
108
236
|
},
|
|
109
237
|
userOptions,
|
|
110
|
-
logger
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
238
|
+
logger
|
|
239
|
+
});
|
|
240
|
+
if (autoDiscoverResult.type === "success") {
|
|
241
|
+
autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
|
|
242
|
+
if (userOptions.verbose) {
|
|
243
|
+
logger?.info(`[react-static-client] Re-discovered ${autoDiscoveredFiles.urlMap.size} pages`);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
if (userOptions.verbose) {
|
|
247
|
+
logger?.warn(`[react-static-client] Failed to re-discover pages: ${autoDiscoverResult.error}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
114
250
|
}
|
|
115
|
-
|
|
251
|
+
}
|
|
252
|
+
if (!autoDiscoveredFiles?.urlMap || autoDiscoveredFiles?.urlMap.size === 0) {
|
|
116
253
|
if (userOptions.verbose) {
|
|
117
|
-
|
|
254
|
+
logger?.warn(`[react-static-client] No pages to generate - urlMap is empty (size: ${autoDiscoveredFiles?.urlMap?.size || 0})`);
|
|
255
|
+
logger?.warn(`[react-static-client] autoDiscoveredFiles exists: ${!!autoDiscoveredFiles}, urlMap exists: ${!!autoDiscoveredFiles?.urlMap}`);
|
|
118
256
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (userOptions.verbose) {
|
|
260
|
+
logger?.info(`[react-static-client] Starting static generation with ${autoDiscoveredFiles.urlMap.size} pages`);
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
122
263
|
if (userOptions.verbose) {
|
|
123
|
-
|
|
264
|
+
logger?.info(`[react-static-client] Attempting to get server manifest from shared state`);
|
|
124
265
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
const panicError = handleError({
|
|
137
|
-
error,
|
|
138
|
-
logger: logger,
|
|
139
|
-
panicThreshold: userOptions.panicThreshold,
|
|
140
|
-
context: "buildStart",
|
|
141
|
-
});
|
|
142
|
-
if (panicError != null) {
|
|
143
|
-
rscWorker?.terminate();
|
|
144
|
-
throw panicError;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
266
|
+
const sharedState = getSharedManifestStore(closeBundleContext);
|
|
267
|
+
if (sharedState.server) {
|
|
268
|
+
serverManifest = sharedState.server;
|
|
269
|
+
if (userOptions.verbose) {
|
|
270
|
+
logger?.info(`[react-static-client] Got server manifest from shared state`);
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
throw new Error("No server manifest in shared state");
|
|
147
274
|
}
|
|
148
|
-
|
|
149
|
-
async renderStart() {
|
|
150
|
-
timing.renderStart = performance.now();
|
|
275
|
+
} catch (error) {
|
|
151
276
|
if (userOptions.verbose) {
|
|
152
|
-
|
|
277
|
+
logger?.info(`[react-static-client] Failed to get server manifest from shared state, trying filesystem: ${error}`);
|
|
153
278
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
279
|
+
const serverManifestPath = join(
|
|
280
|
+
userOptions.build.outDir,
|
|
281
|
+
userOptions.build.server
|
|
282
|
+
);
|
|
283
|
+
const manifestPath = typeof resolvedConfig?.build.manifest === "string" ? resolvedConfig.build.manifest : ".vite/manifest.json";
|
|
284
|
+
if (userOptions.verbose) {
|
|
285
|
+
logger?.info(`[react-static-client] Loading server manifest from: ${join(serverManifestPath, manifestPath)}`);
|
|
286
|
+
}
|
|
287
|
+
const serverManifestResult = await tryManifest({
|
|
288
|
+
root: userOptions.projectRoot,
|
|
289
|
+
outDir: serverManifestPath,
|
|
290
|
+
manifestPath,
|
|
291
|
+
ssrManifest: false
|
|
292
|
+
});
|
|
293
|
+
if (serverManifestResult.type === "error") {
|
|
294
|
+
if (userOptions.verbose) {
|
|
295
|
+
logger?.warn(`[react-static-client] Failed to load server manifest: ${serverManifestResult.error}`);
|
|
296
|
+
}
|
|
297
|
+
serverManifest = {};
|
|
298
|
+
if (userOptions.verbose) {
|
|
299
|
+
logger?.warn(`[react-static-client] Using empty server manifest as fallback`);
|
|
300
|
+
}
|
|
301
|
+
} else if (serverManifestResult.type === "skip") {
|
|
302
|
+
if (userOptions.verbose) {
|
|
303
|
+
logger?.warn(`[react-static-client] Server manifest not found, using empty manifest as fallback`);
|
|
304
|
+
}
|
|
305
|
+
serverManifest = {};
|
|
306
|
+
} else {
|
|
307
|
+
serverManifest = serverManifestResult.manifest;
|
|
308
|
+
if (userOptions.verbose) {
|
|
309
|
+
logger?.info(`[react-static-client] Loaded server manifest from filesystem`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const staticManifestResult = await tryManifest({
|
|
314
|
+
root: userOptions.projectRoot,
|
|
315
|
+
outDir: join(userOptions.build.outDir, userOptions.build.static),
|
|
316
|
+
manifestPath: resolvedConfig?.build.manifest ?? ".vite/manifest.json",
|
|
317
|
+
ssrManifest: false
|
|
318
|
+
});
|
|
319
|
+
if (staticManifestResult.type === "error") {
|
|
320
|
+
throw staticManifestResult.error;
|
|
321
|
+
}
|
|
322
|
+
const staticManifest = staticManifestResult.manifest;
|
|
323
|
+
const indexHtml = staticManifest?.["index.html"]?.file;
|
|
324
|
+
const serverPipeableStreamOptions = {
|
|
325
|
+
...userOptions.serverPipeableStreamOptions,
|
|
326
|
+
bootstrapModules: [
|
|
327
|
+
...indexHtml ? [baseURL(indexHtml)] : [],
|
|
328
|
+
...userOptions.serverPipeableStreamOptions?.bootstrapModules ?? []
|
|
329
|
+
]
|
|
330
|
+
};
|
|
331
|
+
userOptions.serverPipeableStreamOptions = serverPipeableStreamOptions;
|
|
332
|
+
const clientPipeableStreamOptions = {
|
|
333
|
+
...userOptions.clientPipeableStreamOptions,
|
|
334
|
+
bootstrapModules: [
|
|
335
|
+
...indexHtml ? [baseURL(indexHtml)] : [],
|
|
336
|
+
...userOptions.clientPipeableStreamOptions?.bootstrapModules ?? []
|
|
337
|
+
]
|
|
338
|
+
};
|
|
339
|
+
const { cssFilesByPage, globalCss } = processCssFilesForPages({
|
|
340
|
+
userOptions,
|
|
341
|
+
autoDiscoveredFiles,
|
|
342
|
+
serverManifest,
|
|
343
|
+
staticManifest,
|
|
344
|
+
bundle: staticBundle || {},
|
|
345
|
+
logger
|
|
346
|
+
});
|
|
347
|
+
if (userOptions.verbose) {
|
|
348
|
+
for (const [route, cssMap] of cssFilesByPage.entries()) {
|
|
349
|
+
logger.info(
|
|
350
|
+
`[react-static-client] Route ${route}: ${cssMap.size} CSS files`
|
|
351
|
+
);
|
|
352
|
+
for (const [key, value] of cssMap.entries()) {
|
|
353
|
+
logger.info(
|
|
354
|
+
`[react-static-client] CSS file: ${key} -> ${value.as} (${value.children ? "inline" : "link"})`
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const routes = Array.from(
|
|
360
|
+
autoDiscoveredFiles.urlMap.keys()
|
|
361
|
+
);
|
|
362
|
+
if (routes.length === 0) {
|
|
363
|
+
if (userOptions.verbose) {
|
|
364
|
+
logger?.info(
|
|
365
|
+
"[react-static-client] No pages to generate, skipping static generation"
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (userOptions.verbose) {
|
|
371
|
+
logger?.info(`[react-static-client] Creating build loader`);
|
|
372
|
+
}
|
|
373
|
+
const buildLoader = createBuildLoader();
|
|
374
|
+
if (userOptions.verbose) {
|
|
375
|
+
logger?.info(`[react-static-client] Build loader created`);
|
|
376
|
+
}
|
|
377
|
+
if (userOptions.verbose) {
|
|
378
|
+
logger?.info(
|
|
379
|
+
`[react-static-client] Creating RSC worker with path: ${userOptions.rscWorkerPath}`
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const workerStartTime = performance.now();
|
|
383
|
+
let rscWorkerResult;
|
|
384
|
+
try {
|
|
385
|
+
rscWorkerResult = await createWorker({
|
|
386
|
+
projectRoot: userOptions.projectRoot,
|
|
387
|
+
workerPath: userOptions.rscWorkerPath,
|
|
388
|
+
currentCondition: "react-client",
|
|
389
|
+
reverseCondition: "react-server",
|
|
390
|
+
maxListeners: Math.max(routes.length * 3, 10),
|
|
391
|
+
// Account for multiple listeners per route
|
|
392
|
+
envPrefix: envPrefixFromConfig(resolvedConfig),
|
|
393
|
+
logger,
|
|
394
|
+
verbose: userOptions.verbose,
|
|
395
|
+
mode: getNodeEnv(),
|
|
396
|
+
workerData: {
|
|
397
|
+
userOptions: serializedOptions(userOptions, autoDiscoveredFiles),
|
|
398
|
+
resolvedConfig: serializeResolvedConfig(resolvedConfig),
|
|
399
|
+
configEnv: (() => {
|
|
400
|
+
const fallback = resolvedConfig ? {
|
|
401
|
+
command: resolvedConfig.command,
|
|
402
|
+
mode: resolvedConfig.mode,
|
|
403
|
+
isSsrBuild: false,
|
|
404
|
+
isPreview: false
|
|
405
|
+
} : void 0;
|
|
406
|
+
const finalConfigEnv = configEnv || fallback;
|
|
407
|
+
return finalConfigEnv;
|
|
408
|
+
})(),
|
|
409
|
+
serverManifest: serverManifest || {},
|
|
410
|
+
// Use server manifest for page component resolution
|
|
411
|
+
bundle: staticBundle || {},
|
|
412
|
+
// Use static bundle (client build) for page component resolution
|
|
413
|
+
staticBundle: staticBundle || {},
|
|
414
|
+
// Pass static bundle separately for path resolution
|
|
415
|
+
id: "static-client-rsc-worker"
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
} catch (workerError) {
|
|
419
|
+
if (userOptions.verbose) {
|
|
420
|
+
logger?.error(`[react-static-client] Error creating RSC worker: ${workerError}`);
|
|
421
|
+
}
|
|
422
|
+
throw workerError;
|
|
423
|
+
}
|
|
424
|
+
if (rscWorkerResult.type !== "success") {
|
|
425
|
+
const err = rscWorkerResult.error ?? new Error(`Failed to create RSC worker`);
|
|
426
|
+
if (userOptions.verbose) {
|
|
427
|
+
logger?.error(
|
|
428
|
+
`[react-static-client] RSC worker creation failed, throwing error`,
|
|
429
|
+
{ error: err }
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
throw err;
|
|
433
|
+
}
|
|
434
|
+
rscWorker = rscWorkerResult.worker;
|
|
435
|
+
if (userOptions.verbose) {
|
|
436
|
+
logger?.info(`[react-static-client] RSC worker created successfully`);
|
|
437
|
+
}
|
|
438
|
+
const workerStartupTime = performance.now() - workerStartTime;
|
|
439
|
+
if (userOptions.onMetrics) {
|
|
440
|
+
const workerStartupMetric = createWorkerStartupMetrics({
|
|
441
|
+
route: "/",
|
|
442
|
+
// Worker startup is global, not route-specific
|
|
443
|
+
workerType: "rsc",
|
|
444
|
+
// This is the RSC worker for client-side static generation
|
|
445
|
+
startupTime: workerStartupTime,
|
|
446
|
+
fromMainThread: true,
|
|
447
|
+
fromRscWorker: false,
|
|
448
|
+
fromHtmlWorker: false,
|
|
449
|
+
description: `RSC worker startup for client-side static generation`
|
|
163
450
|
});
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
451
|
+
userOptions.onMetrics(workerStartupMetric);
|
|
452
|
+
}
|
|
453
|
+
const { onEvent, onMetrics, ...handlerOptions } = userOptions;
|
|
454
|
+
if (userOptions.verbose) {
|
|
455
|
+
logger?.info(`[react-static-client] Extracted onEvent: ${typeof onEvent}, userOptions.onEvent: ${typeof userOptions.onEvent}`);
|
|
456
|
+
}
|
|
457
|
+
if (!serverBundle && onEvent) {
|
|
458
|
+
const originalOnEvent = onEvent;
|
|
459
|
+
const tempOnEvent = (event) => {
|
|
460
|
+
if (event.type === "build.writeBundle.server") {
|
|
461
|
+
serverBundle = event.data.bundle;
|
|
462
|
+
logger?.info(
|
|
463
|
+
"[react-static-client] Captured server bundle from build event"
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
originalOnEvent(event);
|
|
467
|
+
};
|
|
468
|
+
userOptions.onEvent = tempOnEvent;
|
|
469
|
+
}
|
|
470
|
+
const eventHandler = onEvent || userOptions.onEvent;
|
|
471
|
+
if (typeof eventHandler === "function") {
|
|
167
472
|
try {
|
|
168
|
-
|
|
169
|
-
|
|
473
|
+
if (userOptions.verbose) {
|
|
474
|
+
logger?.info(`[react-static-client] Emitting build.ssg.start event`);
|
|
475
|
+
}
|
|
476
|
+
const r = eventHandler({
|
|
477
|
+
type: "build.ssg.start",
|
|
478
|
+
data: {
|
|
479
|
+
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
480
|
+
options: null,
|
|
481
|
+
// No specific rollup output options for static generation
|
|
482
|
+
bundle: staticBundle || {}
|
|
170
483
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
484
|
+
});
|
|
485
|
+
if (r != null && typeof r === "object" && "then" in r) {
|
|
486
|
+
await r;
|
|
487
|
+
}
|
|
488
|
+
} catch (error) {
|
|
489
|
+
const eventPanicError = handleError({
|
|
490
|
+
error,
|
|
491
|
+
logger,
|
|
492
|
+
panicThreshold: userOptions.panicThreshold,
|
|
493
|
+
context: "onEvent(build.ssg.start)"
|
|
494
|
+
});
|
|
495
|
+
if (eventPanicError != null) {
|
|
496
|
+
throw eventPanicError;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
} else if (userOptions.verbose) {
|
|
500
|
+
logger?.warn(`[react-static-client] No onEvent handler available to emit build.ssg.start`);
|
|
501
|
+
}
|
|
502
|
+
const renderPagesGenerator = renderPagesBatched(
|
|
503
|
+
routes,
|
|
504
|
+
{
|
|
505
|
+
...handlerOptions,
|
|
506
|
+
// Use the clean options instead of the original handlerOptions
|
|
507
|
+
worker: rscWorker,
|
|
508
|
+
// Pass the RSC worker for RSC rendering only
|
|
509
|
+
rscWorker,
|
|
510
|
+
// Pass the RSC worker for RSC rendering only
|
|
511
|
+
loader: buildLoader,
|
|
512
|
+
// Use proper build loader instead of no-op
|
|
513
|
+
logger,
|
|
514
|
+
autoDiscoveredFiles,
|
|
515
|
+
cssFilesByPage,
|
|
516
|
+
// Pass CSS files by page
|
|
517
|
+
serverPipeableStreamOptions,
|
|
518
|
+
// Pass server options to RSC worker
|
|
519
|
+
clientPipeableStreamOptions,
|
|
520
|
+
// Pass client options to RSC worker
|
|
521
|
+
globalCss,
|
|
522
|
+
// Pass global CSS
|
|
523
|
+
manifest: serverManifest || {},
|
|
524
|
+
// Server manifest for RSC worker
|
|
525
|
+
staticManifest,
|
|
526
|
+
// Static manifest for consistent module IDs
|
|
527
|
+
onEvent,
|
|
528
|
+
onMetrics
|
|
529
|
+
// Pass through the onMetrics callback (metric watcher)
|
|
530
|
+
},
|
|
531
|
+
renderPage
|
|
532
|
+
);
|
|
533
|
+
let finalResult = void 0;
|
|
534
|
+
try {
|
|
535
|
+
for await (const result of renderPagesGenerator) {
|
|
536
|
+
if (result.type === "error") {
|
|
537
|
+
if (userOptions.verbose) {
|
|
538
|
+
logger?.error(`[react-static-client] Render error: ${result.error}`);
|
|
180
539
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
let value = normalized[1];
|
|
190
|
-
if (value.startsWith(userOptions.moduleBasePath)) {
|
|
191
|
-
value = value.slice(userOptions.moduleBasePath.length);
|
|
192
|
-
}
|
|
193
|
-
const entry = staticManifest[value];
|
|
194
|
-
if (entry && entry.file !== chunk.fileName) {
|
|
195
|
-
// Update the filename to match static manifest
|
|
196
|
-
chunk.fileName = entry.file;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
540
|
+
throw result.error;
|
|
541
|
+
}
|
|
542
|
+
if (result.type === "success" && result.failedRoutes && result.failedRoutes.size > 0) {
|
|
543
|
+
const firstError = result.failedRoutes.values().next().value;
|
|
544
|
+
if (firstError != null && shouldCausePanic(firstError, {
|
|
545
|
+
panicThreshold: userOptions.panicThreshold
|
|
546
|
+
})) {
|
|
547
|
+
throw firstError;
|
|
201
548
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
549
|
+
for (const [route, error] of result.failedRoutes) {
|
|
550
|
+
const err = error instanceof Error ? error : toError(error);
|
|
551
|
+
closeBundleContext.warn(
|
|
552
|
+
new Error(
|
|
553
|
+
"Failed to render route: " + route + "\n" + err.message + "\n" + err.stack,
|
|
554
|
+
{ cause: err }
|
|
555
|
+
)
|
|
556
|
+
);
|
|
205
557
|
}
|
|
206
|
-
|
|
207
|
-
|
|
558
|
+
}
|
|
559
|
+
finalResult = result;
|
|
208
560
|
}
|
|
209
|
-
|
|
210
|
-
const panicError = handleError({
|
|
211
|
-
error,
|
|
212
|
-
logger: logger,
|
|
213
|
-
panicThreshold: userOptions.panicThreshold,
|
|
214
|
-
context: "writeBundle",
|
|
215
|
-
});
|
|
216
|
-
if (panicError != null) {
|
|
217
|
-
throw panicError;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
async closeBundle() {
|
|
222
|
-
const envName = this.environment.name;
|
|
223
|
-
const isSsr = this.environment.config.build?.ssr === true;
|
|
561
|
+
} catch (renderError) {
|
|
224
562
|
if (userOptions.verbose) {
|
|
225
|
-
|
|
563
|
+
logger?.error(`[react-static-client] Error during renderPages: ${renderError}`);
|
|
226
564
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return;
|
|
565
|
+
throw renderError;
|
|
566
|
+
}
|
|
567
|
+
if (!finalResult) {
|
|
568
|
+
const errorMsg = "No render result produced";
|
|
569
|
+
if (userOptions.verbose) {
|
|
570
|
+
logger?.error(`[react-static-client] ${errorMsg}`);
|
|
234
571
|
}
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
logger?.warn(`[react-static-client] Failed to clean up _virtual directory: ${error}`);
|
|
265
|
-
}
|
|
572
|
+
throw new Error(errorMsg);
|
|
573
|
+
}
|
|
574
|
+
if (userOptions.verbose) {
|
|
575
|
+
logger?.info(`[react-static-client] Render completed: ${finalResult.completedRoutes.size} pages, ${finalResult.failedRoutes?.size || 0} failed`);
|
|
576
|
+
}
|
|
577
|
+
const duration = Math.round(
|
|
578
|
+
performance.now() - (timing.renderStart || timing.start)
|
|
579
|
+
);
|
|
580
|
+
closeBundleContext.info(
|
|
581
|
+
`Rendered ${finalResult.completedRoutes.size} pages in ${duration}ms`
|
|
582
|
+
);
|
|
583
|
+
if (process.env["NODE_ENV"] !== "production") {
|
|
584
|
+
closeBundleContext.warn(
|
|
585
|
+
`THIS BUILD IS NOT INTENDED FOR PRODUCTION (${process.env["NODE_ENV"]})`
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
timing.render = performance.now() - (timing.renderStart ?? timing.start);
|
|
589
|
+
if (userOptions.verbose) {
|
|
590
|
+
logger?.info("[react-static-client] Static generation completed");
|
|
591
|
+
}
|
|
592
|
+
if (typeof userOptions.onEvent === "function") {
|
|
593
|
+
try {
|
|
594
|
+
const r = userOptions.onEvent({
|
|
595
|
+
type: "build.ssg.end",
|
|
596
|
+
data: {
|
|
597
|
+
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
598
|
+
options: null,
|
|
599
|
+
// No specific rollup output options for static generation
|
|
600
|
+
bundle: staticBundle || {}
|
|
266
601
|
}
|
|
602
|
+
});
|
|
603
|
+
if (r != null && typeof r === "object" && "then" in r) {
|
|
604
|
+
await r;
|
|
605
|
+
}
|
|
606
|
+
} catch (error) {
|
|
607
|
+
const eventPanicError = handleError({
|
|
608
|
+
error,
|
|
609
|
+
logger,
|
|
610
|
+
panicThreshold: userOptions.panicThreshold,
|
|
611
|
+
context: "onEvent(build.ssg.end)"
|
|
612
|
+
});
|
|
613
|
+
if (eventPanicError != null) {
|
|
614
|
+
throw eventPanicError;
|
|
615
|
+
}
|
|
267
616
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
617
|
+
}
|
|
618
|
+
} catch (error) {
|
|
619
|
+
const panicError = handleError({
|
|
620
|
+
error,
|
|
621
|
+
logger,
|
|
622
|
+
panicThreshold: userOptions.panicThreshold
|
|
623
|
+
});
|
|
624
|
+
if (rscWorker) {
|
|
625
|
+
const workerToCleanup = rscWorker;
|
|
626
|
+
try {
|
|
627
|
+
await Promise.race([
|
|
628
|
+
new Promise((resolve) => {
|
|
629
|
+
const timeoutId = setTimeout(() => {
|
|
630
|
+
workerToCleanup.removeAllListeners();
|
|
631
|
+
workerToCleanup.terminate();
|
|
632
|
+
resolve();
|
|
633
|
+
}, 1e3);
|
|
634
|
+
const messageHandler = (message) => {
|
|
635
|
+
if (message.type === "SHUTDOWN_COMPLETE") {
|
|
636
|
+
clearTimeout(timeoutId);
|
|
637
|
+
workerToCleanup.removeListener("message", messageHandler);
|
|
638
|
+
resolve();
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
workerToCleanup.on("message", messageHandler);
|
|
642
|
+
workerToCleanup.postMessage({ type: "SHUTDOWN" });
|
|
643
|
+
})
|
|
644
|
+
]);
|
|
645
|
+
rscWorker = void 0;
|
|
646
|
+
} catch (cleanupError) {
|
|
647
|
+
logger.warn(`Failed to cleanup worker on error: ${cleanupError}`);
|
|
648
|
+
try {
|
|
649
|
+
workerToCleanup.removeAllListeners();
|
|
650
|
+
workerToCleanup.terminate();
|
|
651
|
+
} catch (terminateError) {
|
|
652
|
+
}
|
|
653
|
+
rscWorker = void 0;
|
|
276
654
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
655
|
+
}
|
|
656
|
+
if (panicError != null) {
|
|
657
|
+
const errorToThrow = panicError instanceof Error ? panicError : new Error(String(panicError));
|
|
658
|
+
const finalError = new Error(errorToThrow.message);
|
|
659
|
+
finalError.stack = errorToThrow.stack;
|
|
660
|
+
finalError.cause = errorToThrow.cause;
|
|
661
|
+
if (errorToThrow.name) finalError.name = errorToThrow.name;
|
|
662
|
+
throw finalError;
|
|
663
|
+
}
|
|
664
|
+
} finally {
|
|
665
|
+
if (rscWorker) {
|
|
666
|
+
try {
|
|
667
|
+
await Promise.race([
|
|
668
|
+
new Promise((resolve, reject) => {
|
|
669
|
+
const timeout = setTimeout(() => {
|
|
670
|
+
reject(new Error("Worker shutdown timeout"));
|
|
671
|
+
}, userOptions.workerShutdownTimeout);
|
|
672
|
+
const backupTimeout = setTimeout(() => {
|
|
673
|
+
reject(new Error("Worker shutdown backup timeout"));
|
|
674
|
+
}, Math.floor(userOptions.workerShutdownTimeout * 0.6));
|
|
675
|
+
const shutdownMessageHandler = (message) => {
|
|
676
|
+
if (message.type === "SHUTDOWN_COMPLETE") {
|
|
677
|
+
clearTimeout(timeout);
|
|
678
|
+
clearTimeout(backupTimeout);
|
|
679
|
+
rscWorker?.removeListener(
|
|
680
|
+
"message",
|
|
681
|
+
shutdownMessageHandler
|
|
682
|
+
);
|
|
683
|
+
rscWorker?.removeAllListeners();
|
|
684
|
+
resolve();
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
rscWorker?.on("message", shutdownMessageHandler);
|
|
688
|
+
rscWorker?.postMessage({
|
|
689
|
+
type: "SHUTDOWN",
|
|
690
|
+
id: "*"
|
|
691
|
+
});
|
|
692
|
+
})
|
|
693
|
+
]);
|
|
694
|
+
} catch {
|
|
695
|
+
} finally {
|
|
696
|
+
if (rscWorker) {
|
|
283
697
|
try {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (userOptions.verbose) {
|
|
288
|
-
logger?.warn("[react-static-client] autoDiscoveredFiles not set, attempting to re-discover");
|
|
289
|
-
}
|
|
290
|
-
const { getStashedUserOptions, getEnvironmentId } = await import("../config/stashedOptionsState.js");
|
|
291
|
-
const { getCondition } = await import("../config/getCondition.js");
|
|
292
|
-
const envId = getEnvironmentId(getCondition(), resolvedConfig?.mode || "production");
|
|
293
|
-
const stashedOptions = getStashedUserOptions(envId);
|
|
294
|
-
if (stashedOptions && resolvedConfig) {
|
|
295
|
-
// Try to re-run auto-discovery if we have the config
|
|
296
|
-
const autoDiscoverResult = await resolveAutoDiscover({
|
|
297
|
-
config: resolvedConfig,
|
|
298
|
-
configEnv: configEnv || {
|
|
299
|
-
mode: resolvedConfig.mode || "production",
|
|
300
|
-
command: resolvedConfig.command || "build",
|
|
301
|
-
isSsrBuild: false,
|
|
302
|
-
isPreview: false,
|
|
303
|
-
},
|
|
304
|
-
userOptions,
|
|
305
|
-
logger,
|
|
306
|
-
});
|
|
307
|
-
if (autoDiscoverResult.type === "success") {
|
|
308
|
-
autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
|
|
309
|
-
if (userOptions.verbose) {
|
|
310
|
-
logger?.info(`[react-static-client] Re-discovered ${autoDiscoveredFiles.urlMap.size} pages`);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
if (userOptions.verbose) {
|
|
315
|
-
logger?.warn(`[react-static-client] Failed to re-discover pages: ${autoDiscoverResult.error}`);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
if (!autoDiscoveredFiles?.urlMap ||
|
|
321
|
-
autoDiscoveredFiles?.urlMap.size === 0) {
|
|
322
|
-
if (userOptions.verbose) {
|
|
323
|
-
logger?.warn(`[react-static-client] No pages to generate - urlMap is empty (size: ${autoDiscoveredFiles?.urlMap?.size || 0})`);
|
|
324
|
-
logger?.warn(`[react-static-client] autoDiscoveredFiles exists: ${!!autoDiscoveredFiles}, urlMap exists: ${!!autoDiscoveredFiles?.urlMap}`);
|
|
325
|
-
}
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (userOptions.verbose) {
|
|
329
|
-
logger?.info(`[react-static-client] Starting static generation with ${autoDiscoveredFiles.urlMap.size} pages`);
|
|
330
|
-
}
|
|
331
|
-
// Check if we can access the shared manifest store
|
|
332
|
-
try {
|
|
333
|
-
if (userOptions.verbose) {
|
|
334
|
-
logger?.info(`[react-static-client] Attempting to get server manifest from shared state`);
|
|
335
|
-
}
|
|
336
|
-
const sharedState = getSharedManifestStore(closeBundleContext);
|
|
337
|
-
if (sharedState.server) {
|
|
338
|
-
serverManifest = sharedState.server;
|
|
339
|
-
if (userOptions.verbose) {
|
|
340
|
-
logger?.info(`[react-static-client] Got server manifest from shared state`);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
throw new Error("No server manifest in shared state");
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
catch (error) {
|
|
348
|
-
if (userOptions.verbose) {
|
|
349
|
-
logger?.info(`[react-static-client] Failed to get server manifest from shared state, trying filesystem: ${error}`);
|
|
350
|
-
}
|
|
351
|
-
const serverManifestPath = join(userOptions.build.outDir, userOptions.build.server);
|
|
352
|
-
const manifestPath = (typeof resolvedConfig?.build.manifest === "string"
|
|
353
|
-
? resolvedConfig.build.manifest
|
|
354
|
-
: ".vite/manifest.json");
|
|
355
|
-
if (userOptions.verbose) {
|
|
356
|
-
logger?.info(`[react-static-client] Loading server manifest from: ${join(serverManifestPath, manifestPath)}`);
|
|
357
|
-
}
|
|
358
|
-
const serverManifestResult = await tryManifest({
|
|
359
|
-
root: userOptions.projectRoot,
|
|
360
|
-
outDir: serverManifestPath,
|
|
361
|
-
manifestPath: manifestPath,
|
|
362
|
-
ssrManifest: false,
|
|
363
|
-
});
|
|
364
|
-
if (serverManifestResult.type === "error") {
|
|
365
|
-
if (userOptions.verbose) {
|
|
366
|
-
logger?.warn(`[react-static-client] Failed to load server manifest: ${serverManifestResult.error}`);
|
|
367
|
-
}
|
|
368
|
-
// Use empty manifest as fallback - static generation can proceed without it
|
|
369
|
-
serverManifest = {};
|
|
370
|
-
if (userOptions.verbose) {
|
|
371
|
-
logger?.warn(`[react-static-client] Using empty server manifest as fallback`);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
else if (serverManifestResult.type === "skip") {
|
|
375
|
-
if (userOptions.verbose) {
|
|
376
|
-
logger?.warn(`[react-static-client] Server manifest not found, using empty manifest as fallback`);
|
|
377
|
-
}
|
|
378
|
-
// Use empty manifest as fallback - static generation can proceed without it
|
|
379
|
-
serverManifest = {};
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
serverManifest = serverManifestResult.manifest;
|
|
383
|
-
if (userOptions.verbose) {
|
|
384
|
-
logger?.info(`[react-static-client] Loaded server manifest from filesystem`);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
// Load static manifest from filesystem for CSS path mapping
|
|
389
|
-
const staticManifestResult = await tryManifest({
|
|
390
|
-
root: userOptions.projectRoot,
|
|
391
|
-
outDir: join(userOptions.build.outDir, userOptions.build.static),
|
|
392
|
-
manifestPath: resolvedConfig?.build.manifest ?? ".vite/manifest.json",
|
|
393
|
-
ssrManifest: false,
|
|
394
|
-
});
|
|
395
|
-
if (staticManifestResult.type === "error") {
|
|
396
|
-
throw staticManifestResult.error;
|
|
397
|
-
}
|
|
398
|
-
const staticManifest = staticManifestResult.manifest;
|
|
399
|
-
// Construct bootstrapModules like the server plugin does
|
|
400
|
-
const indexHtml = staticManifest?.["index.html"]?.file;
|
|
401
|
-
const serverPipeableStreamOptions = {
|
|
402
|
-
...userOptions.serverPipeableStreamOptions,
|
|
403
|
-
bootstrapModules: [
|
|
404
|
-
...(indexHtml ? [baseURL(indexHtml)] : []),
|
|
405
|
-
...(userOptions.serverPipeableStreamOptions?.bootstrapModules ??
|
|
406
|
-
[]),
|
|
407
|
-
],
|
|
408
|
-
};
|
|
409
|
-
userOptions.serverPipeableStreamOptions = serverPipeableStreamOptions;
|
|
410
|
-
const clientPipeableStreamOptions = {
|
|
411
|
-
...userOptions.clientPipeableStreamOptions,
|
|
412
|
-
bootstrapModules: [
|
|
413
|
-
...(indexHtml ? [baseURL(indexHtml)] : []),
|
|
414
|
-
...(userOptions.clientPipeableStreamOptions?.bootstrapModules ??
|
|
415
|
-
[]),
|
|
416
|
-
],
|
|
417
|
-
};
|
|
418
|
-
// Create CSS props for each CSS file (same as server-static)
|
|
419
|
-
const { cssFilesByPage, globalCss } = processCssFilesForPages({
|
|
420
|
-
userOptions,
|
|
421
|
-
autoDiscoveredFiles,
|
|
422
|
-
serverManifest,
|
|
423
|
-
staticManifest,
|
|
424
|
-
bundle: staticBundle || {},
|
|
425
|
-
logger,
|
|
426
|
-
});
|
|
427
|
-
if (userOptions.verbose) {
|
|
428
|
-
for (const [route, cssMap] of cssFilesByPage.entries()) {
|
|
429
|
-
logger.info(`[react-static-client] Route ${route}: ${cssMap.size} CSS files`);
|
|
430
|
-
for (const [key, value] of cssMap.entries()) {
|
|
431
|
-
logger.info(`[react-static-client] CSS file: ${key} -> ${value.as} (${value.children ? "inline" : "link"})`);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const routes = Array.from(autoDiscoveredFiles.urlMap.keys());
|
|
436
|
-
// If no pages to generate, skip static generation
|
|
437
|
-
if (routes.length === 0) {
|
|
438
|
-
if (userOptions.verbose) {
|
|
439
|
-
logger?.info("[react-static-client] No pages to generate, skipping static generation");
|
|
440
|
-
}
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
// Use the static manifest to ensure consistent module IDs between RSC stream and client build
|
|
444
|
-
// The static manifest contains the correct hashes that should be used for both builds
|
|
445
|
-
// (staticManifest already loaded above)
|
|
446
|
-
// Create a build loader for client mode (reuse server's sophisticated loader)
|
|
447
|
-
if (userOptions.verbose) {
|
|
448
|
-
logger?.info(`[react-static-client] Creating build loader`);
|
|
449
|
-
}
|
|
450
|
-
const buildLoader = createBuildLoader();
|
|
451
|
-
if (userOptions.verbose) {
|
|
452
|
-
logger?.info(`[react-static-client] Build loader created`);
|
|
453
|
-
}
|
|
454
|
-
// Create an RSC worker for generating RSC content
|
|
455
|
-
if (userOptions.verbose) {
|
|
456
|
-
logger?.info(`[react-static-client] Creating RSC worker with path: ${userOptions.rscWorkerPath}`);
|
|
457
|
-
}
|
|
458
|
-
const workerStartTime = performance.now();
|
|
459
|
-
let rscWorkerResult;
|
|
460
|
-
try {
|
|
461
|
-
rscWorkerResult = await createWorker({
|
|
462
|
-
projectRoot: userOptions.projectRoot,
|
|
463
|
-
workerPath: userOptions.rscWorkerPath,
|
|
464
|
-
currentCondition: "react-client",
|
|
465
|
-
reverseCondition: "react-server",
|
|
466
|
-
maxListeners: Math.max(routes.length * 3, 10), // Account for multiple listeners per route
|
|
467
|
-
envPrefix: envPrefixFromConfig(resolvedConfig),
|
|
468
|
-
logger: logger,
|
|
469
|
-
verbose: userOptions.verbose,
|
|
470
|
-
mode: getNodeEnv(),
|
|
471
|
-
workerData: {
|
|
472
|
-
userOptions: serializedOptions(userOptions, autoDiscoveredFiles),
|
|
473
|
-
resolvedConfig: serializeResolvedConfig(resolvedConfig),
|
|
474
|
-
configEnv: (() => {
|
|
475
|
-
const fallback = resolvedConfig
|
|
476
|
-
? {
|
|
477
|
-
command: resolvedConfig.command,
|
|
478
|
-
mode: resolvedConfig.mode,
|
|
479
|
-
isSsrBuild: false,
|
|
480
|
-
isPreview: false,
|
|
481
|
-
}
|
|
482
|
-
: undefined;
|
|
483
|
-
const finalConfigEnv = configEnv || fallback;
|
|
484
|
-
return finalConfigEnv;
|
|
485
|
-
})(),
|
|
486
|
-
serverManifest: serverManifest || {}, // Use server manifest for page component resolution
|
|
487
|
-
bundle: staticBundle || {}, // Use static bundle (client build) for page component resolution
|
|
488
|
-
staticBundle: staticBundle || {}, // Pass static bundle separately for path resolution
|
|
489
|
-
id: "static-client-rsc-worker",
|
|
490
|
-
},
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
catch (workerError) {
|
|
494
|
-
if (userOptions.verbose) {
|
|
495
|
-
logger?.error(`[react-static-client] Error creating RSC worker: ${workerError}`);
|
|
496
|
-
}
|
|
497
|
-
throw workerError;
|
|
498
|
-
}
|
|
499
|
-
if (rscWorkerResult.type !== "success") {
|
|
500
|
-
const err = rscWorkerResult.error ?? new Error(`Failed to create RSC worker`);
|
|
501
|
-
if (userOptions.verbose) {
|
|
502
|
-
logger?.error(`[react-static-client] RSC worker creation failed, throwing error`, { error: err });
|
|
503
|
-
}
|
|
504
|
-
throw err;
|
|
505
|
-
}
|
|
506
|
-
rscWorker = rscWorkerResult.worker;
|
|
507
|
-
if (userOptions.verbose) {
|
|
508
|
-
logger?.info(`[react-static-client] RSC worker created successfully`);
|
|
509
|
-
}
|
|
510
|
-
// Emit worker startup metric after worker is created
|
|
511
|
-
const workerStartupTime = performance.now() - workerStartTime;
|
|
512
|
-
if (userOptions.onMetrics) {
|
|
513
|
-
const workerStartupMetric = createWorkerStartupMetrics({
|
|
514
|
-
route: "/", // Worker startup is global, not route-specific
|
|
515
|
-
workerType: "rsc", // This is the RSC worker for client-side static generation
|
|
516
|
-
startupTime: workerStartupTime,
|
|
517
|
-
fromMainThread: true,
|
|
518
|
-
fromRscWorker: false,
|
|
519
|
-
fromHtmlWorker: false,
|
|
520
|
-
description: `RSC worker startup for client-side static generation`,
|
|
521
|
-
});
|
|
522
|
-
userOptions.onMetrics(workerStartupMetric);
|
|
523
|
-
}
|
|
524
|
-
// Render pages using client-side renderer with RSC worker only
|
|
525
|
-
const { onEvent, onMetrics, ...handlerOptions } = userOptions;
|
|
526
|
-
if (userOptions.verbose) {
|
|
527
|
-
logger?.info(`[react-static-client] Extracted onEvent: ${typeof onEvent}, userOptions.onEvent: ${typeof userOptions.onEvent}`);
|
|
528
|
-
}
|
|
529
|
-
// Capture server bundle from onEvent if not already captured
|
|
530
|
-
if (!serverBundle && onEvent) {
|
|
531
|
-
// Create a temporary event handler to capture the server bundle
|
|
532
|
-
const originalOnEvent = onEvent;
|
|
533
|
-
const tempOnEvent = (event) => {
|
|
534
|
-
if (event.type === "build.writeBundle.server") {
|
|
535
|
-
serverBundle = event.data.bundle;
|
|
536
|
-
logger?.info("[react-static-client] Captured server bundle from build event");
|
|
537
|
-
}
|
|
538
|
-
// Call the original event handler
|
|
539
|
-
originalOnEvent(event);
|
|
540
|
-
};
|
|
541
|
-
// Replace the onEvent temporarily to capture the server bundle
|
|
542
|
-
userOptions.onEvent = tempOnEvent;
|
|
543
|
-
}
|
|
544
|
-
// Emit the static site generation start event
|
|
545
|
-
// Use the extracted onEvent if available, otherwise fall back to userOptions.onEvent
|
|
546
|
-
const eventHandler = onEvent || userOptions.onEvent;
|
|
547
|
-
if (typeof eventHandler === "function") {
|
|
548
|
-
try {
|
|
549
|
-
if (userOptions.verbose) {
|
|
550
|
-
logger?.info(`[react-static-client] Emitting build.ssg.start event`);
|
|
551
|
-
}
|
|
552
|
-
const r = eventHandler({
|
|
553
|
-
type: "build.ssg.start",
|
|
554
|
-
data: {
|
|
555
|
-
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
556
|
-
options: null, // No specific rollup output options for static generation
|
|
557
|
-
bundle: staticBundle || {},
|
|
558
|
-
},
|
|
559
|
-
});
|
|
560
|
-
if (r != null && typeof r === "object" && "then" in r) {
|
|
561
|
-
await r;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
catch (error) {
|
|
565
|
-
const eventPanicError = handleError({
|
|
566
|
-
error,
|
|
567
|
-
logger: logger,
|
|
568
|
-
panicThreshold: userOptions.panicThreshold,
|
|
569
|
-
context: "onEvent(build.ssg.start)",
|
|
570
|
-
});
|
|
571
|
-
if (eventPanicError != null) {
|
|
572
|
-
throw eventPanicError; // Re-throw to abort the build
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
else if (userOptions.verbose) {
|
|
577
|
-
logger?.warn(`[react-static-client] No onEvent handler available to emit build.ssg.start`);
|
|
578
|
-
}
|
|
579
|
-
const renderPagesGenerator = renderPagesBatched(routes, {
|
|
580
|
-
...handlerOptions, // Use the clean options instead of the original handlerOptions
|
|
581
|
-
worker: rscWorker, // Pass the RSC worker for RSC rendering only
|
|
582
|
-
rscWorker: rscWorker, // Pass the RSC worker for RSC rendering only
|
|
583
|
-
loader: buildLoader, // Use proper build loader instead of no-op
|
|
584
|
-
logger: logger,
|
|
585
|
-
autoDiscoveredFiles: autoDiscoveredFiles,
|
|
586
|
-
cssFilesByPage: cssFilesByPage, // Pass CSS files by page
|
|
587
|
-
serverPipeableStreamOptions: serverPipeableStreamOptions, // Pass server options to RSC worker
|
|
588
|
-
clientPipeableStreamOptions: clientPipeableStreamOptions, // Pass client options to RSC worker
|
|
589
|
-
globalCss: globalCss, // Pass global CSS
|
|
590
|
-
manifest: serverManifest || {}, // Server manifest for RSC worker
|
|
591
|
-
staticManifest: staticManifest, // Static manifest for consistent module IDs
|
|
592
|
-
onEvent: onEvent,
|
|
593
|
-
onMetrics: onMetrics, // Pass through the onMetrics callback (metric watcher)
|
|
594
|
-
}, renderPage);
|
|
595
|
-
// Process the rendered pages
|
|
596
|
-
let finalResult = undefined;
|
|
597
|
-
try {
|
|
598
|
-
for await (const result of renderPagesGenerator) {
|
|
599
|
-
if (result.type === "error") {
|
|
600
|
-
if (userOptions.verbose) {
|
|
601
|
-
logger?.error(`[react-static-client] Render error: ${result.error}`);
|
|
602
|
-
}
|
|
603
|
-
throw result.error;
|
|
604
|
-
}
|
|
605
|
-
// Handle failed routes based on panic threshold
|
|
606
|
-
if (result.type === "success" &&
|
|
607
|
-
result.failedRoutes &&
|
|
608
|
-
result.failedRoutes.size > 0) {
|
|
609
|
-
// Use centralized panic threshold logic (same as server plugin)
|
|
610
|
-
const firstError = result.failedRoutes.values().next().value;
|
|
611
|
-
if (firstError != null &&
|
|
612
|
-
shouldCausePanic(firstError, {
|
|
613
|
-
panicThreshold: userOptions.panicThreshold,
|
|
614
|
-
})) {
|
|
615
|
-
// This should cause a panic, throw the error
|
|
616
|
-
throw firstError;
|
|
617
|
-
}
|
|
618
|
-
// For other panic thresholds, log warnings but continue
|
|
619
|
-
for (const [route, error] of result.failedRoutes) {
|
|
620
|
-
const err = error instanceof Error ? error : toError(error);
|
|
621
|
-
closeBundleContext.warn(new Error("Failed to render route: " +
|
|
622
|
-
route +
|
|
623
|
-
"\n" +
|
|
624
|
-
err.message +
|
|
625
|
-
"\n" +
|
|
626
|
-
err.stack, { cause: err }));
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
finalResult = result;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
catch (renderError) {
|
|
633
|
-
if (userOptions.verbose) {
|
|
634
|
-
logger?.error(`[react-static-client] Error during renderPages: ${renderError}`);
|
|
635
|
-
}
|
|
636
|
-
throw renderError;
|
|
637
|
-
}
|
|
638
|
-
if (!finalResult) {
|
|
639
|
-
const errorMsg = "No render result produced";
|
|
640
|
-
if (userOptions.verbose) {
|
|
641
|
-
logger?.error(`[react-static-client] ${errorMsg}`);
|
|
642
|
-
}
|
|
643
|
-
throw new Error(errorMsg);
|
|
644
|
-
}
|
|
645
|
-
if (userOptions.verbose) {
|
|
646
|
-
logger?.info(`[react-static-client] Render completed: ${finalResult.completedRoutes.size} pages, ${finalResult.failedRoutes?.size || 0} failed`);
|
|
647
|
-
}
|
|
648
|
-
// File writes are handled by renderPages, no need to do them here
|
|
649
|
-
// Calculate duration from timing
|
|
650
|
-
const duration = Math.round(performance.now() - (timing.renderStart || timing.start));
|
|
651
|
-
closeBundleContext.info(`Rendered ${finalResult.completedRoutes.size} pages in ${duration}ms`);
|
|
652
|
-
if (process.env["NODE_ENV"] !== "production") {
|
|
653
|
-
closeBundleContext.warn(`THIS BUILD IS NOT INTENDED FOR PRODUCTION (${process.env["NODE_ENV"]})`);
|
|
654
|
-
}
|
|
655
|
-
// Update timing
|
|
656
|
-
timing.render =
|
|
657
|
-
performance.now() - (timing.renderStart ?? timing.start);
|
|
658
|
-
if (userOptions.verbose) {
|
|
659
|
-
logger?.info("[react-static-client] Static generation completed");
|
|
660
|
-
}
|
|
661
|
-
// Emit the static site generation completion event once
|
|
662
|
-
if (typeof userOptions.onEvent === "function") {
|
|
663
|
-
try {
|
|
664
|
-
const r = userOptions.onEvent({
|
|
665
|
-
type: "build.ssg.end",
|
|
666
|
-
data: {
|
|
667
|
-
pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
|
|
668
|
-
options: null, // No specific rollup output options for static generation
|
|
669
|
-
bundle: staticBundle || {},
|
|
670
|
-
},
|
|
671
|
-
});
|
|
672
|
-
if (r != null && typeof r === "object" && "then" in r) {
|
|
673
|
-
await r;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
catch (error) {
|
|
677
|
-
const eventPanicError = handleError({
|
|
678
|
-
error,
|
|
679
|
-
logger: logger,
|
|
680
|
-
panicThreshold: userOptions.panicThreshold,
|
|
681
|
-
context: "onEvent(build.ssg.end)",
|
|
682
|
-
});
|
|
683
|
-
if (eventPanicError != null) {
|
|
684
|
-
throw eventPanicError; // Re-throw to abort the build
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
catch (error) {
|
|
690
|
-
const panicError = handleError({
|
|
691
|
-
error,
|
|
692
|
-
context: "react-static-client",
|
|
693
|
-
logger,
|
|
694
|
-
panicThreshold: userOptions.panicThreshold,
|
|
695
|
-
});
|
|
696
|
-
// Ensure graceful shutdown on error
|
|
697
|
-
if (rscWorker) {
|
|
698
|
-
const workerToCleanup = rscWorker;
|
|
699
|
-
try {
|
|
700
|
-
// Use graceful shutdown protocol even on error
|
|
701
|
-
await Promise.race([
|
|
702
|
-
new Promise((resolve) => {
|
|
703
|
-
const timeoutId = setTimeout(() => {
|
|
704
|
-
workerToCleanup.removeAllListeners();
|
|
705
|
-
workerToCleanup.terminate();
|
|
706
|
-
resolve();
|
|
707
|
-
}, 1000); // 1 second timeout for graceful shutdown
|
|
708
|
-
const messageHandler = (message) => {
|
|
709
|
-
if (message.type === "SHUTDOWN_COMPLETE") {
|
|
710
|
-
clearTimeout(timeoutId);
|
|
711
|
-
workerToCleanup.removeListener("message", messageHandler);
|
|
712
|
-
resolve();
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
workerToCleanup.on("message", messageHandler);
|
|
716
|
-
workerToCleanup.postMessage({ type: "SHUTDOWN" });
|
|
717
|
-
}),
|
|
718
|
-
]);
|
|
719
|
-
rscWorker = undefined;
|
|
720
|
-
}
|
|
721
|
-
catch (cleanupError) {
|
|
722
|
-
logger.warn(`Failed to cleanup worker on error: ${cleanupError}`);
|
|
723
|
-
// Force terminate if graceful shutdown fails
|
|
724
|
-
try {
|
|
725
|
-
workerToCleanup.removeAllListeners();
|
|
726
|
-
workerToCleanup.terminate();
|
|
727
|
-
}
|
|
728
|
-
catch (terminateError) {
|
|
729
|
-
// Ignore termination errors
|
|
730
|
-
}
|
|
731
|
-
rscWorker = undefined;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
if (panicError != null) {
|
|
735
|
-
// Ensure we have a proper Error object that can have properties set on it
|
|
736
|
-
const errorToThrow = panicError instanceof Error
|
|
737
|
-
? panicError
|
|
738
|
-
: new Error(String(panicError));
|
|
739
|
-
// Create a new Error object to avoid the "code" property issue
|
|
740
|
-
const finalError = new Error(errorToThrow.message);
|
|
741
|
-
finalError.stack = errorToThrow.stack;
|
|
742
|
-
finalError.cause = errorToThrow.cause;
|
|
743
|
-
// Copy any additional properties that might be needed
|
|
744
|
-
if (errorToThrow.name)
|
|
745
|
-
finalError.name = errorToThrow.name;
|
|
746
|
-
throw finalError;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
finally {
|
|
750
|
-
// Graceful worker shutdown — runs on both success and error paths
|
|
751
|
-
if (rscWorker) {
|
|
752
|
-
try {
|
|
753
|
-
await Promise.race([
|
|
754
|
-
new Promise((resolve, reject) => {
|
|
755
|
-
const timeout = setTimeout(() => {
|
|
756
|
-
reject(new Error("Worker shutdown timeout"));
|
|
757
|
-
}, userOptions.workerShutdownTimeout);
|
|
758
|
-
const backupTimeout = setTimeout(() => {
|
|
759
|
-
reject(new Error("Worker shutdown backup timeout"));
|
|
760
|
-
}, Math.floor(userOptions.workerShutdownTimeout * 0.6));
|
|
761
|
-
const shutdownMessageHandler = (message) => {
|
|
762
|
-
if (message.type === "SHUTDOWN_COMPLETE") {
|
|
763
|
-
clearTimeout(timeout);
|
|
764
|
-
clearTimeout(backupTimeout);
|
|
765
|
-
rscWorker?.removeListener("message", shutdownMessageHandler);
|
|
766
|
-
rscWorker?.removeAllListeners();
|
|
767
|
-
resolve();
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
rscWorker?.on("message", shutdownMessageHandler);
|
|
771
|
-
rscWorker?.postMessage({
|
|
772
|
-
type: "SHUTDOWN",
|
|
773
|
-
id: "*",
|
|
774
|
-
});
|
|
775
|
-
}),
|
|
776
|
-
]);
|
|
777
|
-
}
|
|
778
|
-
catch {
|
|
779
|
-
// Shutdown protocol failed — force terminate below
|
|
780
|
-
}
|
|
781
|
-
finally {
|
|
782
|
-
if (rscWorker) {
|
|
783
|
-
try {
|
|
784
|
-
rscWorker.removeAllListeners();
|
|
785
|
-
rscWorker.terminate();
|
|
786
|
-
}
|
|
787
|
-
catch {
|
|
788
|
-
// Ignore termination errors
|
|
789
|
-
}
|
|
790
|
-
rscWorker = undefined;
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
// Reset any cached state to prevent issues in subsequent builds
|
|
795
|
-
autoDiscoveredFiles = null;
|
|
796
|
-
serverManifest = undefined;
|
|
698
|
+
rscWorker.removeAllListeners();
|
|
699
|
+
rscWorker.terminate();
|
|
700
|
+
} catch {
|
|
797
701
|
}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
702
|
+
rscWorker = void 0;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
autoDiscoveredFiles = null;
|
|
707
|
+
serverManifest = void 0;
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
};
|
|
801
712
|
};
|
|
713
|
+
|
|
714
|
+
export { reactStaticPlugin };
|
|
715
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmNsaWVudC5qcyIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcGx1Z2luL3JlYWN0LXN0YXRpYy9wbHVnaW4uY2xpZW50LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogcGx1Z2luLmNsaWVudC50c1xuICpcbiAqIFBVUlBPU0U6IENsaWVudC1zaWRlIHN0YXRpYyBwbHVnaW4gZm9yIFJlYWN0IFNlcnZlciBDb21wb25lbnRzXG4gKlxuICogVGhpcyBtb2R1bGU6XG4gKiAxLiBIYW5kbGVzIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gaW4gdGhlIGNsaWVudCBlbnZpcm9ubWVudFxuICogMi4gVXNlcyBSU0Mgd29ya2VyIGZvciBSU0MgcmVuZGVyaW5nIGFuZCBtYWluLXRocmVhZCBmb3IgSFRNTCByZW5kZXJpbmdcbiAqIDMuIEdlbmVyYXRlcyBib3RoIFJTQyBhbmQgSFRNTCBmaWxlcyBmb3Igc3RhdGljIHBhZ2VzXG4gKiA0LiBJbnRlZ3JhdGVzIHdpdGggVml0ZSdzIGJ1aWxkIHByb2Nlc3NcbiAqXG4gKiBGZWF0dXJlIHBhcml0eSB3aXRoIG1haW4gcmVhY3Qtc3RhdGljIHBsdWdpbiwgYnV0IGluIHJldmVyc2UuIFVzZXMgcnNjLXdvcmtlciB0byByZW5kZXIgcnNjLCBhbmQgbWFpbiB0aHJlYWQgZm9yIGh0bWwuXG4gKiBUaGlzIGlzIG5vdCB0aGUgZGVmYXVsdCBiZWhhdmlvciwgYnV0IGlzIHN1cHBvcnRlZCBmb3IgdGVzdGluZyBhbmQgY3VzdG9tIGFwcCBkZXZlbG9wbWVudCBwdXJwb3Nlcy5cbiAqIEFkZGl0aW9uYWxseSwgdGhpcyBjYW4gbWFrZSBpdCBlYXNpZXIgdG8gdXNlIHRoZSAtLWFwcCBmbGFnIHRvIGJ1aWxkIGFsbCB0aGUgbW9kdWxlcyArIHN0YXRpYyBnZW5lcmF0aW9uIGF0IG9uY2UuXG4gKi9cblxuaW1wb3J0IHtcbiAgY3JlYXRlTG9nZ2VyLFxuICB0eXBlIFJlc29sdmVkQ29uZmlnLFxuICB0eXBlIE1hbmlmZXN0LFxuICB0eXBlIENvbmZpZ0Vudixcbn0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCB7IHJlc29sdmVPcHRpb25zIH0gZnJvbSBcIi4uL2NvbmZpZy9yZXNvbHZlT3B0aW9ucy5qc1wiO1xuaW1wb3J0IHR5cGUge1xuICBCdWlsZFRpbWluZyxcbiAgVml0ZVBsdWdpbkZuLFxuICBBdXRvRGlzY292ZXJlZEZpbGVzLFxufSBmcm9tIFwiLi4vdHlwZXMuanNcIjtcbmltcG9ydCB0eXBlIHsgT3V0cHV0QnVuZGxlIH0gZnJvbSBcInJvbGx1cFwiO1xuaW1wb3J0IHsgcmVuZGVyUGFnZXNCYXRjaGVkIH0gZnJvbSBcIi4vcmVuZGVyUGFnZXNCYXRjaGVkLmpzXCI7XG5pbXBvcnQgeyBwZXJmb3JtYW5jZSB9IGZyb20gXCJub2RlOnBlcmZfaG9va3NcIjtcbmltcG9ydCB7IHJlbmRlclBhZ2UgfSBmcm9tIFwiLi9yZW5kZXJQYWdlLmNsaWVudC5qc1wiO1xuXG5pbXBvcnQgeyBjcmVhdGVXb3JrZXIgfSBmcm9tIFwiLi4vd29ya2VyL2NyZWF0ZVdvcmtlci5qc1wiO1xuaW1wb3J0IHtcbiAgc2VyaWFsaXplZE9wdGlvbnMsXG4gIHNlcmlhbGl6ZVJlc29sdmVkQ29uZmlnLFxufSBmcm9tIFwiLi4vaGVscGVycy9zZXJpYWxpemVVc2VyT3B0aW9ucy5qc1wiO1xuaW1wb3J0IHsgZ2V0QnVuZGxlTWFuaWZlc3QgfSBmcm9tIFwiLi4vaGVscGVycy9nZXRCdW5kbGVNYW5pZmVzdC5qc1wiO1xuXG5pbXBvcnQgeyBoYW5kbGVFcnJvciB9IGZyb20gXCIuLi9lcnJvci9oYW5kbGVFcnJvci5qc1wiO1xuaW1wb3J0IHsgc2hvdWxkQ2F1c2VQYW5pYyB9IGZyb20gXCIuLi9lcnJvci9wYW5pY1RocmVzaG9sZEhhbmRsZXIuanNcIjtcbmltcG9ydCB7IGNvbmZpZ3VyZVByZXZpZXdTZXJ2ZXIgfSBmcm9tIFwiLi9jb25maWd1cmVQcmV2aWV3U2VydmVyLmpzXCI7XG5pbXBvcnQgeyBhc3NlcnROb25SZWFjdFNlcnZlciB9IGZyb20gXCIuLi9jb25maWcvZ2V0Q29uZGl0aW9uLmpzXCI7XG5pbXBvcnQgeyBlbnZQcmVmaXhGcm9tQ29uZmlnIH0gZnJvbSBcIi4uL2NvbmZpZy9lbnZQcmVmaXhGcm9tQ29uZmlnLmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVXb3JrZXJTdGFydHVwTWV0cmljcyB9IGZyb20gXCIuLi9tZXRyaWNzL2NyZWF0ZVdvcmtlclN0YXJ0dXBNZXRyaWNzLmpzXCI7XG5pbXBvcnQgeyBwcm9jZXNzQ3NzRmlsZXNGb3JQYWdlcyB9IGZyb20gXCIuL3Byb2Nlc3NDc3NGaWxlc0ZvclBhZ2VzLmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVCdWlsZExvYWRlciB9IGZyb20gXCIuL2NyZWF0ZUJ1aWxkTG9hZGVyLmNsaWVudC5qc1wiO1xuaW1wb3J0IHsgZ2V0Tm9kZUVudiB9IGZyb20gXCIuLi9jb25maWcvZ2V0Tm9kZUVudi5qc1wiO1xuaW1wb3J0IHsgdG9FcnJvciB9IGZyb20gXCIuLi9lcnJvci90b0Vycm9yLmpzXCI7XG5pbXBvcnQge1xuICBhZGRTdGF0aWNNYW5pZmVzdCxcbiAgbWFuaWZlc3RzLFxuICBnZXRTaGFyZWRNYW5pZmVzdFN0b3JlLFxufSBmcm9tIFwiLi4vYnVuZGxlL21hbmlmZXN0cy5qc1wiO1xuaW1wb3J0IHsgZGVmZXJTdGF0aWNHZW5lcmF0aW9uIH0gZnJvbSBcIi4uL2J1bmRsZS9kZWZlcnJlZFN0YXRpY0dlbmVyYXRpb24uanNcIjtcbmltcG9ydCB0eXBlIHsgV29ya2VyIH0gZnJvbSBcIm5vZGU6d29ya2VyX3RocmVhZHNcIjtcbmltcG9ydCB7IHJlc29sdmVBdXRvRGlzY292ZXIgfSBmcm9tIFwiLi4vY29uZmlnL2luZGV4LmpzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG5pbXBvcnQgeyBiYXNlVVJMIH0gZnJvbSBcIi4uL3V0aWxzL2VudlVybHMubm9kZS5qc1wiO1xuaW1wb3J0IHsgdHJ5TWFuaWZlc3QgfSBmcm9tIFwiLi4vaGVscGVycy90cnlNYW5pZmVzdC5qc1wiO1xuLy8gY3NzQ29sbGVjdG9yIHJlbW92ZWQgLSB1c2luZyBmaWxlc3lzdGVtLWJhc2VkIENTUyBwcm9jZXNzaW5nXG5cbmFzc2VydE5vblJlYWN0U2VydmVyKCk7XG5cbi8qKlxuICogcGx1Z2luLmNsaWVudC50c1xuICpcbiAqIFBVUlBPU0U6IENsaWVudC1zaWRlIHN0YXRpYyBwbHVnaW4gZm9yIFJlYWN0IFNlcnZlciBDb21wb25lbnRzXG4gKlxuICogVGhpcyBtb2R1bGU6XG4gKiAxLiBIYW5kbGVzIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gaW4gdGhlIGNsaWVudCBlbnZpcm9ubWVudFxuICogMi4gVXNlcyBSU0Mgd29ya2VyIGZvciBSU0MgcmVuZGVyaW5nIGFuZCBtYWluLXRocmVhZCBmb3IgSFRNTCByZW5kZXJpbmdcbiAqIDMuIEdlbmVyYXRlcyBib3RoIFJTQyBhbmQgSFRNTCBmaWxlcyBmb3Igc3RhdGljIHBhZ2VzXG4gKiA0LiBJbnRlZ3JhdGVzIHdpdGggVml0ZSdzIGJ1aWxkIHByb2Nlc3NcbiAqXG4gKiBAcGFyYW0gb3B0aW9uc1xuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGNvbnN0IHJlYWN0U3RhdGljUGx1Z2luOiBWaXRlUGx1Z2luRm4gPSBmdW5jdGlvbiBfcmVhY3RTdGF0aWNQbHVnaW4oXG4gIG9wdGlvbnNcbikge1xuICBsZXQgbG9nZ2VyOiBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVMb2dnZXI+O1xuICBsZXQgYXV0b0Rpc2NvdmVyZWRGaWxlczogQXV0b0Rpc2NvdmVyZWRGaWxlcyB8IG51bGwgPSBudWxsO1xuICBsZXQgcnNjV29ya2VyOiBXb3JrZXIgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIGxldCByZXNvbHZlZENvbmZpZzogUmVzb2x2ZWRDb25maWcgfCBudWxsID0gbnVsbDtcbiAgbGV0IHNlcnZlck1hbmlmZXN0OiBNYW5pZmVzdCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgbGV0IHN0YXRpY0J1bmRsZTogT3V0cHV0QnVuZGxlIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICBsZXQgc2VydmVyQnVuZGxlOiBPdXRwdXRCdW5kbGUgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5cbiAgbGV0IGNvbmZpZ0VudjogQ29uZmlnRW52IHwgdW5kZWZpbmVkO1xuICBjb25zdCB0aW1pbmc6IEJ1aWxkVGltaW5nID0ge1xuICAgIHN0YXJ0OiBwZXJmb3JtYW5jZS5ub3coKSxcbiAgICBjb25maWdSZXNvbHZlZDogMCxcbiAgICBidWlsZFN0YXJ0OiAwLFxuICAgIHJlbmRlclN0YXJ0OiAwLFxuICB9O1xuXG4gIGNvbnN0IHJlc29sdmVkT3B0aW9ucyA9IHJlc29sdmVPcHRpb25zKG9wdGlvbnMpO1xuICBpZiAocmVzb2x2ZWRPcHRpb25zLnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgIHRocm93IHJlc29sdmVkT3B0aW9ucy5lcnJvcjtcbiAgfVxuICBjb25zdCB1c2VyT3B0aW9ucyA9IHJlc29sdmVkT3B0aW9ucy51c2VyT3B0aW9ucztcblxuICByZXR1cm4ge1xuICAgIG5hbWU6IFwidml0ZTpwbHVnaW4tcmVhY3Qtc2VydmVyL2NsaWVudC1zdGF0aWNcIixcbiAgICBlbmZvcmNlOiBcInBvc3RcIixcbiAgICBhcHBseTogXCJidWlsZFwiLCAvLyBBcHBseSB0byBidWlsZCBtb2RlXG4gICAgYXBpOiB7XG4gICAgICBtZXRhOiB7IHRpbWluZyB9LFxuICAgIH0sXG4gICAgYXN5bmMgY29uZmlnKF9jb25maWcsIHZpdGVDb25maWdFbnYpIHtcbiAgICAgIGNvbmZpZ0VudiA9IHZpdGVDb25maWdFbnY7XG4gICAgfSxcbiAgICBhcHBseVRvRW52aXJvbm1lbnQocGFydGlhbEVudmlyb25tZW50KSB7XG4gICAgICAvLyBDbGllbnQgc3RhdGljIHBsdWdpbiBzaG91bGQgYXBwbHkgdG8gc3RhdGljIGVudmlyb25tZW50IChicm93c2VyL0VTTSBidWlsZHMpXG4gICAgICAvLyBUaGlzIGlzIHdoZXJlIHdlIHdhbnQgdG8gYnVuZGxlIGV2ZXJ5dGhpbmcgYW5kIGZpbHRlciBvdXQgX3ZpcnR1YWwgZmlsZXNcbiAgICAgIC8vIEFwcGx5IHRvIGJvdGggXCJzdGF0aWNcIiBhbmQgXCJjbGllbnRcIiBlbnZpcm9ubWVudHMgLSB3ZSdsbCBoYW5kbGUgd2hpY2ggb25lIHJ1bnMgc3RhdGljIGdlbmVyYXRpb24gaW4gY2xvc2VCdW5kbGVcbiAgICAgIGNvbnN0IGVudk5hbWUgPSBwYXJ0aWFsRW52aXJvbm1lbnQubmFtZSBhcyBcImNsaWVudFwiIHwgXCJzZXJ2ZXJcIiB8IFwic3NyXCIgfCBcInN0YXRpY1wiO1xuICAgICAgaWYgKFxuICAgICAgICBbXCJzdGF0aWNcIiwgXCJjbGllbnRcIl0uaW5jbHVkZXMoZW52TmFtZSlcbiAgICAgICkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9LFxuXG4gICAgYXN5bmMgY29uZmlnUmVzb2x2ZWQoY29uZmlnKSB7XG4gICAgICB0aW1pbmcuY29uZmlnUmVzb2x2ZWQgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgIGxvZ2dlciA9IGNvbmZpZy5jdXN0b21Mb2dnZXIgfHwgY3JlYXRlTG9nZ2VyKCk7XG4gICAgICByZXNvbHZlZENvbmZpZyA9IGNvbmZpZztcblxuICAgICAgLy8gUGVyZm9ybSBhdXRvLWRpc2NvdmVyeSB0byBwb3B1bGF0ZSBhdXRvRGlzY292ZXJlZEZpbGVzXG4gICAgICBjb25zdCBhdXRvRGlzY292ZXJSZXN1bHQgPSBhd2FpdCByZXNvbHZlQXV0b0Rpc2NvdmVyKHtcbiAgICAgICAgY29uZmlnOiBjb25maWcsXG4gICAgICAgIGNvbmZpZ0VudjogY29uZmlnRW52IHx8IHtcbiAgICAgICAgICBtb2RlOiBjb25maWcubW9kZSxcbiAgICAgICAgICBjb21tYW5kOiBjb25maWcuY29tbWFuZCxcbiAgICAgICAgICBpc1NzckJ1aWxkOiBmYWxzZSxcbiAgICAgICAgICBpc1ByZXZpZXc6IGZhbHNlLFxuICAgICAgICB9LFxuICAgICAgICB1c2VyT3B0aW9ucyxcbiAgICAgICAgbG9nZ2VyLFxuICAgICAgfSk7XG4gICAgICBpZiAoYXV0b0Rpc2NvdmVyUmVzdWx0LnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgICAgICB0aHJvdyBhdXRvRGlzY292ZXJSZXN1bHQuZXJyb3I7XG4gICAgICB9XG4gICAgICBhdXRvRGlzY292ZXJlZEZpbGVzID0gYXV0b0Rpc2NvdmVyUmVzdWx0LmF1dG9EaXNjb3ZlcmVkRmlsZXM7XG4gICAgICBpZih1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgIGxvZ2dlcj8uaW5mbyhgQXV0by1kaXNjb3ZlcnkgJHthdXRvRGlzY292ZXJSZXN1bHQudHlwZSA9PT0gXCJzdWNjZXNzXCIgPyBcImNvbXBsZXRlZFwiIDogXCJza2lwcGVkXCJ9YCk7XG4gICAgICB9XG4gICAgfSxcblxuICAgIGFzeW5jIGJ1aWxkU3RhcnQoKSB7XG4gICAgICB0aW1pbmcuYnVpbGRTdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgICAgaWYodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICBsb2dnZXI/LmluZm8oXCJbcmVhY3Qtc3RhdGljLWNsaWVudF0gQnVpbGQgc3RhcnRlZFwiKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHVzZXJPcHRpb25zLm9uRXZlbnQgJiYgYXV0b0Rpc2NvdmVyZWRGaWxlcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHVzZXJPcHRpb25zLm9uRXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogXCJidWlsZC5zdGFydFwiLFxuICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5rZXlzKCkpLFxuICAgICAgICAgICAgICBmaWxlczogYXV0b0Rpc2NvdmVyZWRGaWxlcyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc3QgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgICBjb250ZXh0OiBcImJ1aWxkU3RhcnRcIixcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAocGFuaWNFcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgICByc2NXb3JrZXI/LnRlcm1pbmF0ZSgpO1xuICAgICAgICAgIHRocm93IHBhbmljRXJyb3I7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcblxuICAgIGFzeW5jIHJlbmRlclN0YXJ0KCkge1xuICAgICAgdGltaW5nLnJlbmRlclN0YXJ0ID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgICBpZih1c2VyT3B0aW9ucy52ZXJib3NlKSB7IFxuICAgICAgICBsb2dnZXI/LmluZm8oXCJbcmVhY3Qtc3RhdGljLWNsaWVudF0gUmVuZGVyIHN0YXJ0ZWRcIik7XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8vIHRoZSBwcmV2aWV3IHNlcnZlciBoZWxwcyB0byB2aWV3IHRoZSBnZW5lcmF0ZWQgc3RhdGljIGZvbGRlciwgYnV0IG9ubHkgd2hlbiB0aGUgc3RhdGljIHBsdWdpbiBpcyBlbmFibGVkXG4gICAgLy8gaWYgbm8gYnVpbGQucGFnZXMsIHRoZW4gdGhlIHByZXZpZXcgc2VydmVyIHdpbGwgaW5zdGVhZCB1c2UgZGVmYXVsdCB2aXRlIHByZXZpZXcgc2VydmVyXG4gICAgLy8gaXQgd29ya3MgdGhlIHNhbWUgdW5kZXIgYm90aCBjb25kaXRpb25zXG4gICAgYXN5bmMgY29uZmlndXJlUHJldmlld1NlcnZlcihzZXJ2ZXIpIHtcbiAgICAgIGxvZ2dlciA9IHNlcnZlci5jb25maWcuY3VzdG9tTG9nZ2VyIHx8IHNlcnZlci5jb25maWcubG9nZ2VyO1xuICAgICAgY29uZmlndXJlUHJldmlld1NlcnZlcih7XG4gICAgICAgIHNlcnZlcixcbiAgICAgICAgdXNlck9wdGlvbnMsXG4gICAgICB9KTtcbiAgICB9LFxuXG5cblxuICAgIGFzeW5jIHdyaXRlQnVuZGxlKF9vcHRpb25zLCBidW5kbGUpIHtcblxuICAgICAgLy8gQ2FwdHVyZSBtYW5pZmVzdHMgZnJvbSBhbGwgZW52aXJvbm1lbnRzXG4gICAgICB0cnkge1xuICAgICAgICBpZiAoIWF1dG9EaXNjb3ZlcmVkRmlsZXM/LnVybE1hcCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1bmRsZU1hbmlmZXN0ID0gZ2V0QnVuZGxlTWFuaWZlc3Q8ZmFsc2U+KHtcbiAgICAgICAgICBidW5kbGUsXG4gICAgICAgICAgbm9ybWFsaXplcjogdXNlck9wdGlvbnMubm9ybWFsaXplcixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gU3RvcmUgbWFuaWZlc3QgYmFzZWQgb24gZW52aXJvbm1lbnRcbiAgICAgICAgaWYgKHRoaXMuZW52aXJvbm1lbnQubmFtZSA9PT0gXCJzdGF0aWNcIikge1xuICAgICAgICAgIC8vIFN0b3JlIGluIGdsb2JhbCBtYW5pZmVzdCBzdG9yZSBmb3IgZW52aXJvbm1lbnQgcGx1Z2luIGFjY2Vzc1xuICAgICAgICAgIGFkZFN0YXRpY01hbmlmZXN0KGJ1bmRsZU1hbmlmZXN0KTtcblxuICAgICAgICAgIHN0YXRpY0J1bmRsZSA9IGJ1bmRsZTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmVudmlyb25tZW50Lm5hbWUgPT09IFwiY2xpZW50XCIpIHtcbiAgICAgICAgICAvLyBDbGllbnQgYnVpbGQgbWFuaWZlc3QgKFNTUiBtb2R1bGVzKSAtIHN0b3JlZCBnbG9iYWxseSBub3dcblxuICAgICAgICAgIGlmIChtYW5pZmVzdHMuc3RhdGljKSB7XG4gICAgICAgICAgICBjb25zdCBzdGF0aWNNYW5pZmVzdCA9IG1hbmlmZXN0cy5zdGF0aWM7XG5cbiAgICAgICAgICAgIC8vIFVwZGF0ZSBidW5kbGUgZmlsZW5hbWVzIHRvIG1hdGNoIHN0YXRpYyBtYW5pZmVzdFxuICAgICAgICAgICAgZm9yIChjb25zdCBbLCBjaHVua10gb2YgT2JqZWN0LmVudHJpZXMoYnVuZGxlKSkge1xuICAgICAgICAgICAgICBpZiAoY2h1bmsudHlwZSA9PT0gXCJjaHVua1wiICYmIGNodW5rLmZpbGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IHVzZXJPcHRpb25zLm5vcm1hbGl6ZXIoY2h1bmsuZmlsZU5hbWUpO1xuICAgICAgICAgICAgICAgIGxldCB2YWx1ZSA9IG5vcm1hbGl6ZWRbMV07XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlLnN0YXJ0c1dpdGgodXNlck9wdGlvbnMubW9kdWxlQmFzZVBhdGgpKSB7XG4gICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKHVzZXJPcHRpb25zLm1vZHVsZUJhc2VQYXRoLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgZW50cnkgPSBzdGF0aWNNYW5pZmVzdFt2YWx1ZV07XG4gICAgICAgICAgICAgICAgaWYgKGVudHJ5ICYmIGVudHJ5LmZpbGUgIT09IGNodW5rLmZpbGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAvLyBVcGRhdGUgdGhlIGZpbGVuYW1lIHRvIG1hdGNoIHN0YXRpYyBtYW5pZmVzdFxuICAgICAgICAgICAgICAgICAgY2h1bmsuZmlsZU5hbWUgPSBlbnRyeS5maWxlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmVudmlyb25tZW50Lm5hbWUgPT09IFwic2VydmVyXCIpIHtcbiAgICAgICAgICAvLyBTZXJ2ZXIgYnVpbGQgbWFuaWZlc3QgKHNlcnZlciBjb21wb25lbnRzKSAtIHN0b3JlZCBnbG9iYWxseSBub3dcbiAgICAgICAgICBzZXJ2ZXJCdW5kbGUgPSBidW5kbGU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTa2lwIHRoZSBzdGF0aWMgZ2VuZXJhdGlvbiBoZXJlIC0gaXQgd2lsbCBoYXBwZW4gaW4gY2xvc2VCdW5kbGVcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc3QgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgY29udGV4dDogXCJ3cml0ZUJ1bmRsZVwiLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgIHRocm93IHBhbmljRXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuXG4gICAgYXN5bmMgY2xvc2VCdW5kbGUoKSB7XG4gICAgICBjb25zdCBlbnZOYW1lID0gdGhpcy5lbnZpcm9ubWVudC5uYW1lO1xuICAgICAgY29uc3QgaXNTc3IgPSB0aGlzLmVudmlyb25tZW50LmNvbmZpZy5idWlsZD8uc3NyID09PSB0cnVlO1xuICAgICAgXG4gICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBjbG9zZUJ1bmRsZSBjYWxsZWQgZm9yIGVudmlyb25tZW50OiAke2Vudk5hbWV9LCBzc3I6ICR7aXNTc3J9YCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIE9ubHkgcnVuIHN0YXRpYyBnZW5lcmF0aW9uIGluIHRoZSBub24tU1NSIGNsaWVudCBlbnZpcm9ubWVudCAoc3RhdGljIGJ1aWxkcylcbiAgICAgIC8vIFNraXAgU1NSIGNsaWVudCBidWlsZHMgYW5kIHNlcnZlciBidWlsZHNcbiAgICAgIGlmIChlbnZOYW1lID09PSBcInNzclwiIHx8IGVudk5hbWUgPT09IFwic2VydmVyXCIgfHwgaXNTc3IpIHtcbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBTa2lwcGluZyBzdGF0aWMgZ2VuZXJhdGlvbiBmb3IgZW52aXJvbm1lbnQ6ICR7ZW52TmFtZX0gKHNzcjogJHtpc1Nzcn0pYCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBDbGVhbiB1cCBfdmlydHVhbCBmaWxlcyBhZnRlciBidWlsZCBjb21wbGV0ZXNcbiAgICAgIC8vIFRoZXNlIGFyZSBWaXRlJ3MgaW50ZXJuYWwgdmlydHVhbCBtb2R1bGVzIGFuZCBhcmVuJ3QgbmVlZGVkIGluIHRoZSBmaW5hbCBvdXRwdXRcbiAgICAgIGlmIChlbnZOYW1lID09PSBcInN0YXRpY1wiIHx8IChlbnZOYW1lID09PSBcImNsaWVudFwiICYmICFpc1NzcikpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB7IHJtU3luYywgZXhpc3RzU3luYyB9ID0gYXdhaXQgaW1wb3J0KFwibm9kZTpmc1wiKTtcbiAgICAgICAgICBjb25zdCB7IGpvaW4sIHJlc29sdmUgfSA9IGF3YWl0IGltcG9ydChcIm5vZGU6cGF0aFwiKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBVc2UgdGhlIHJlc29sdmVkIG91dHB1dCBkaXJlY3RvcnkgZnJvbSB0aGUgZW52aXJvbm1lbnQgY29uZmlnXG4gICAgICAgICAgY29uc3QgcmVzb2x2ZWRPdXREaXIgPSB0aGlzLmVudmlyb25tZW50LmNvbmZpZy5idWlsZD8ub3V0RGlyIFxuICAgICAgICAgICAgPyByZXNvbHZlKHRoaXMuZW52aXJvbm1lbnQuY29uZmlnLnJvb3QgfHwgdXNlck9wdGlvbnMucHJvamVjdFJvb3QsIHRoaXMuZW52aXJvbm1lbnQuY29uZmlnLmJ1aWxkLm91dERpcilcbiAgICAgICAgICAgIDogcmVzb2x2ZSh1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCwgdXNlck9wdGlvbnMuYnVpbGQub3V0RGlyKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBDbGVhbiB1cCBfdmlydHVhbCBmcm9tIGNsaWVudC9zdGF0aWMgb3V0cHV0IGRpcmVjdG9yaWVzIG9ubHlcbiAgICAgICAgICAvLyBEb24ndCBjbGVhbiB1cCBzZXJ2ZXIvX3ZpcnR1YWwgc2luY2Ugd2UgbmVlZCBkeW5hbWljLWltcG9ydC1oZWxwZXIuanMgdGhlcmVcbiAgICAgICAgICBjb25zdCBvdXRwdXREaXJzID0gW1xuICAgICAgICAgICAgam9pbihyZXNvbHZlZE91dERpciwgdXNlck9wdGlvbnMuYnVpbGQuc3RhdGljIHx8IFwic3RhdGljXCIpLFxuICAgICAgICAgICAgam9pbihyZXNvbHZlZE91dERpciwgdXNlck9wdGlvbnMuYnVpbGQuY2xpZW50IHx8IFwiY2xpZW50XCIpLFxuICAgICAgICAgIF07XG4gICAgICAgICAgXG4gICAgICAgICAgZm9yIChjb25zdCBvdXREaXIgb2Ygb3V0cHV0RGlycykge1xuICAgICAgICAgICAgY29uc3QgdmlydHVhbERpciA9IGpvaW4ob3V0RGlyLCBcIl92aXJ0dWFsXCIpO1xuICAgICAgICAgICAgaWYgKGV4aXN0c1N5bmModmlydHVhbERpcikpIHtcbiAgICAgICAgICAgICAgcm1TeW5jKHZpcnR1YWxEaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBDbGVhbmVkIHVwIF92aXJ0dWFsIGRpcmVjdG9yeTogJHt2aXJ0dWFsRGlyfWApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIC8vIE5vbi1jcml0aWNhbCAtIGxvZyBidXQgZG9uJ3QgZmFpbCB0aGUgYnVpbGRcbiAgICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgbG9nZ2VyPy53YXJuKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gRmFpbGVkIHRvIGNsZWFuIHVwIF92aXJ0dWFsIGRpcmVjdG9yeTogJHtlcnJvcn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gVGhpcyBydW5zIGFmdGVyIGFsbCB3cml0ZUJ1bmRsZSBob29rcyBhcmUgY29tcGxldGVcbiAgICAgIC8vIFJ1biBzdGF0aWMgZ2VuZXJhdGlvbiBpbiB0aGUgbm9uLVNTUiBjbGllbnQgZW52aXJvbm1lbnQgKHN0YXRpYyBidWlsZHMpXG4gICAgICAvLyBUaGlzIGNvdWxkIGJlIFwic3RhdGljXCIgb3IgXCJjbGllbnRcIiBkZXBlbmRpbmcgb24gaG93IGVudmlyb25tZW50cyBhcmUgY29uZmlndXJlZFxuICAgICAgaWYgKGVudk5hbWUgPT09IFwic3NyXCIgfHwgZW52TmFtZSA9PT0gXCJzZXJ2ZXJcIiB8fCBpc1Nzcikge1xuICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFNraXBwaW5nIHN0YXRpYyBnZW5lcmF0aW9uIC0gbm90IGluIHN0YXRpYyBlbnZpcm9ubWVudCAoJHtlbnZOYW1lfSwgc3NyOiAke2lzU3NyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIERlZmVyIHN0YXRpYyBnZW5lcmF0aW9uIHRvIHJ1biBhZnRlciBBTEwgZW52aXJvbm1lbnRzIGNvbXBsZXRlIHRoZWlyIGJ1aWxkcy5cbiAgICAgIC8vIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2Ugd2UgbmVlZCB0aGUgc2VydmVyIG1hbmlmZXN0IChmcm9tIHNlcnZlciBlbnYncyB3cml0ZUJ1bmRsZSlcbiAgICAgIC8vIHRvIHJlc29sdmUgZnVuY3Rpb24tYmFzZWQgY29tcG9uZW50IHBhdGhzIGxpa2UgUm9vdDogKHVybCkgPT4gJ3NyYy9DdXN0b21Sb290LnRzeCcuXG4gICAgICAvLyBUaGUgYnVpbGRBcHAgaG9vayBpbiBjcmVhdGVFbnZpcm9ubWVudFBsdWdpbiB3aWxsIGNhbGwgcnVuRGVmZXJyZWRTdGF0aWNHZW5lcmF0aW9uKCkuXG4gICAgICBjb25zdCBjbG9zZUJ1bmRsZUNvbnRleHQgPSB0aGlzO1xuICAgICAgZGVmZXJTdGF0aWNHZW5lcmF0aW9uKGFzeW5jICgpID0+IHtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gUmUtY2hlY2sgYXV0b0Rpc2NvdmVyZWRGaWxlcyAtIGl0IG1pZ2h0IG5vdCBiZSBzZXQgaWYgY29uZmlnUmVzb2x2ZWQgZGlkbid0IHJ1blxuICAgICAgICAvLyBvciBpZiBpdCB3YXMgY2xlYXJlZC4gVHJ5IHRvIGdldCBpdCBmcm9tIHN0YXNoZWQgb3B0aW9ucyBpZiBuZWVkZWRcbiAgICAgICAgaWYgKCFhdXRvRGlzY292ZXJlZEZpbGVzKSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8ud2FybihcIltyZWFjdC1zdGF0aWMtY2xpZW50XSBhdXRvRGlzY292ZXJlZEZpbGVzIG5vdCBzZXQsIGF0dGVtcHRpbmcgdG8gcmUtZGlzY292ZXJcIik7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IHsgZ2V0U3Rhc2hlZFVzZXJPcHRpb25zLCBnZXRFbnZpcm9ubWVudElkIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9jb25maWcvc3Rhc2hlZE9wdGlvbnNTdGF0ZS5qc1wiKTtcbiAgICAgICAgICBjb25zdCB7IGdldENvbmRpdGlvbiB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vY29uZmlnL2dldENvbmRpdGlvbi5qc1wiKTtcbiAgICAgICAgICBjb25zdCBlbnZJZCA9IGdldEVudmlyb25tZW50SWQoZ2V0Q29uZGl0aW9uKCksIHJlc29sdmVkQ29uZmlnPy5tb2RlIHx8IFwicHJvZHVjdGlvblwiKTtcbiAgICAgICAgICBjb25zdCBzdGFzaGVkT3B0aW9ucyA9IGdldFN0YXNoZWRVc2VyT3B0aW9ucyhlbnZJZCk7XG4gICAgICAgICAgaWYgKHN0YXNoZWRPcHRpb25zICYmIHJlc29sdmVkQ29uZmlnKSB7XG4gICAgICAgICAgICAvLyBUcnkgdG8gcmUtcnVuIGF1dG8tZGlzY292ZXJ5IGlmIHdlIGhhdmUgdGhlIGNvbmZpZ1xuICAgICAgICAgICAgY29uc3QgYXV0b0Rpc2NvdmVyUmVzdWx0ID0gYXdhaXQgcmVzb2x2ZUF1dG9EaXNjb3Zlcih7XG4gICAgICAgICAgICAgIGNvbmZpZzogcmVzb2x2ZWRDb25maWcsXG4gICAgICAgICAgICAgIGNvbmZpZ0VudjogY29uZmlnRW52IHx8IHtcbiAgICAgICAgICAgICAgICBtb2RlOiByZXNvbHZlZENvbmZpZy5tb2RlIHx8IFwicHJvZHVjdGlvblwiLFxuICAgICAgICAgICAgICAgIGNvbW1hbmQ6IHJlc29sdmVkQ29uZmlnLmNvbW1hbmQgfHwgXCJidWlsZFwiLFxuICAgICAgICAgICAgICAgIGlzU3NyQnVpbGQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzUHJldmlldzogZmFsc2UsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHVzZXJPcHRpb25zLFxuICAgICAgICAgICAgICBsb2dnZXIsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChhdXRvRGlzY292ZXJSZXN1bHQudHlwZSA9PT0gXCJzdWNjZXNzXCIpIHtcbiAgICAgICAgICAgICAgYXV0b0Rpc2NvdmVyZWRGaWxlcyA9IGF1dG9EaXNjb3ZlclJlc3VsdC5hdXRvRGlzY292ZXJlZEZpbGVzO1xuICAgICAgICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFJlLWRpc2NvdmVyZWQgJHthdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5zaXplfSBwYWdlc2ApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlcj8ud2FybihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEZhaWxlZCB0byByZS1kaXNjb3ZlciBwYWdlczogJHthdXRvRGlzY292ZXJSZXN1bHQuZXJyb3J9YCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoXG4gICAgICAgICAgIWF1dG9EaXNjb3ZlcmVkRmlsZXM/LnVybE1hcCB8fFxuICAgICAgICAgIGF1dG9EaXNjb3ZlcmVkRmlsZXM/LnVybE1hcC5zaXplID09PSAwXG4gICAgICAgICkge1xuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/Lndhcm4oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBObyBwYWdlcyB0byBnZW5lcmF0ZSAtIHVybE1hcCBpcyBlbXB0eSAoc2l6ZTogJHthdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXA/LnNpemUgfHwgMH0pYCk7XG4gICAgICAgICAgICBsb2dnZXI/Lndhcm4oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBhdXRvRGlzY292ZXJlZEZpbGVzIGV4aXN0czogJHshIWF1dG9EaXNjb3ZlcmVkRmlsZXN9LCB1cmxNYXAgZXhpc3RzOiAkeyEhYXV0b0Rpc2NvdmVyZWRGaWxlcz8udXJsTWFwfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFN0YXJ0aW5nIHN0YXRpYyBnZW5lcmF0aW9uIHdpdGggJHthdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5zaXplfSBwYWdlc2ApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgd2UgY2FuIGFjY2VzcyB0aGUgc2hhcmVkIG1hbmlmZXN0IHN0b3JlXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEF0dGVtcHRpbmcgdG8gZ2V0IHNlcnZlciBtYW5pZmVzdCBmcm9tIHNoYXJlZCBzdGF0ZWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBzaGFyZWRTdGF0ZSA9IGdldFNoYXJlZE1hbmlmZXN0U3RvcmUoY2xvc2VCdW5kbGVDb250ZXh0KTtcbiAgICAgICAgICBpZiAoc2hhcmVkU3RhdGUuc2VydmVyKSB7XG4gICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdCA9IHNoYXJlZFN0YXRlLnNlcnZlcjtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEdvdCBzZXJ2ZXIgbWFuaWZlc3QgZnJvbSBzaGFyZWQgc3RhdGVgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gc2VydmVyIG1hbmlmZXN0IGluIHNoYXJlZCBzdGF0ZVwiKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEZhaWxlZCB0byBnZXQgc2VydmVyIG1hbmlmZXN0IGZyb20gc2hhcmVkIHN0YXRlLCB0cnlpbmcgZmlsZXN5c3RlbTogJHtlcnJvcn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qgc2VydmVyTWFuaWZlc3RQYXRoID0gam9pbihcbiAgICAgICAgICAgIHVzZXJPcHRpb25zLmJ1aWxkLm91dERpcixcbiAgICAgICAgICAgIHVzZXJPcHRpb25zLmJ1aWxkLnNlcnZlclxuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3QgbWFuaWZlc3RQYXRoID1cbiAgICAgICAgICAgICh0eXBlb2YgcmVzb2x2ZWRDb25maWc/LmJ1aWxkLm1hbmlmZXN0ID09PSBcInN0cmluZ1wiIFxuICAgICAgICAgICAgICA/IHJlc29sdmVkQ29uZmlnLmJ1aWxkLm1hbmlmZXN0IFxuICAgICAgICAgICAgICA6IFwiLnZpdGUvbWFuaWZlc3QuanNvblwiKTtcblxuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBMb2FkaW5nIHNlcnZlciBtYW5pZmVzdCBmcm9tOiAke2pvaW4oc2VydmVyTWFuaWZlc3RQYXRoLCBtYW5pZmVzdFBhdGgpfWApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHNlcnZlck1hbmlmZXN0UmVzdWx0ID0gYXdhaXQgdHJ5TWFuaWZlc3Qoe1xuICAgICAgICAgICAgcm9vdDogdXNlck9wdGlvbnMucHJvamVjdFJvb3QsXG4gICAgICAgICAgICBvdXREaXI6IHNlcnZlck1hbmlmZXN0UGF0aCxcbiAgICAgICAgICAgIG1hbmlmZXN0UGF0aDogbWFuaWZlc3RQYXRoLFxuICAgICAgICAgICAgc3NyTWFuaWZlc3Q6IGZhbHNlLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKHNlcnZlck1hbmlmZXN0UmVzdWx0LnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgbG9nZ2VyPy53YXJuKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gRmFpbGVkIHRvIGxvYWQgc2VydmVyIG1hbmlmZXN0OiAke3NlcnZlck1hbmlmZXN0UmVzdWx0LmVycm9yfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gVXNlIGVtcHR5IG1hbmlmZXN0IGFzIGZhbGxiYWNrIC0gc3RhdGljIGdlbmVyYXRpb24gY2FuIHByb2NlZWQgd2l0aG91dCBpdFxuICAgICAgICAgICAgc2VydmVyTWFuaWZlc3QgPSB7fTtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8ud2FybihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFVzaW5nIGVtcHR5IHNlcnZlciBtYW5pZmVzdCBhcyBmYWxsYmFja2ApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAoc2VydmVyTWFuaWZlc3RSZXN1bHQudHlwZSA9PT0gXCJza2lwXCIpIHtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8ud2FybihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFNlcnZlciBtYW5pZmVzdCBub3QgZm91bmQsIHVzaW5nIGVtcHR5IG1hbmlmZXN0IGFzIGZhbGxiYWNrYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBVc2UgZW1wdHkgbWFuaWZlc3QgYXMgZmFsbGJhY2sgLSBzdGF0aWMgZ2VuZXJhdGlvbiBjYW4gcHJvY2VlZCB3aXRob3V0IGl0XG4gICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdCA9IHt9O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdCA9IHNlcnZlck1hbmlmZXN0UmVzdWx0Lm1hbmlmZXN0O1xuICAgICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgbG9nZ2VyPy5pbmZvKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gTG9hZGVkIHNlcnZlciBtYW5pZmVzdCBmcm9tIGZpbGVzeXN0ZW1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBMb2FkIHN0YXRpYyBtYW5pZmVzdCBmcm9tIGZpbGVzeXN0ZW0gZm9yIENTUyBwYXRoIG1hcHBpbmdcblxuICAgICAgICBjb25zdCBzdGF0aWNNYW5pZmVzdFJlc3VsdCA9IGF3YWl0IHRyeU1hbmlmZXN0KHtcbiAgICAgICAgICByb290OiB1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCxcbiAgICAgICAgICBvdXREaXI6IGpvaW4odXNlck9wdGlvbnMuYnVpbGQub3V0RGlyLCB1c2VyT3B0aW9ucy5idWlsZC5zdGF0aWMpLFxuICAgICAgICAgIG1hbmlmZXN0UGF0aDogcmVzb2x2ZWRDb25maWc/LmJ1aWxkLm1hbmlmZXN0ID8/IFwiLnZpdGUvbWFuaWZlc3QuanNvblwiLFxuICAgICAgICAgIHNzck1hbmlmZXN0OiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChzdGF0aWNNYW5pZmVzdFJlc3VsdC50eXBlID09PSBcImVycm9yXCIpIHtcbiAgICAgICAgICB0aHJvdyBzdGF0aWNNYW5pZmVzdFJlc3VsdC5lcnJvcjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzdGF0aWNNYW5pZmVzdCA9IHN0YXRpY01hbmlmZXN0UmVzdWx0Lm1hbmlmZXN0O1xuXG4gICAgICAgIC8vIENvbnN0cnVjdCBib290c3RyYXBNb2R1bGVzIGxpa2UgdGhlIHNlcnZlciBwbHVnaW4gZG9lc1xuICAgICAgICBjb25zdCBpbmRleEh0bWwgPSBzdGF0aWNNYW5pZmVzdD8uW1wiaW5kZXguaHRtbFwiXT8uZmlsZTtcbiAgICAgICAgY29uc3Qgc2VydmVyUGlwZWFibGVTdHJlYW1PcHRpb25zID0ge1xuICAgICAgICAgIC4uLnVzZXJPcHRpb25zLnNlcnZlclBpcGVhYmxlU3RyZWFtT3B0aW9ucyxcbiAgICAgICAgICBib290c3RyYXBNb2R1bGVzOiBbXG4gICAgICAgICAgICAuLi4oaW5kZXhIdG1sID8gW2Jhc2VVUkwoaW5kZXhIdG1sKV0gOiBbXSksXG4gICAgICAgICAgICAuLi4odXNlck9wdGlvbnMuc2VydmVyUGlwZWFibGVTdHJlYW1PcHRpb25zPy5ib290c3RyYXBNb2R1bGVzID8/XG4gICAgICAgICAgICAgIFtdKSxcbiAgICAgICAgICBdLFxuICAgICAgICB9O1xuICAgICAgICB1c2VyT3B0aW9ucy5zZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnMgPSBzZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnM7XG4gICAgICAgIGNvbnN0IGNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucyA9IHtcbiAgICAgICAgICAuLi51c2VyT3B0aW9ucy5jbGllbnRQaXBlYWJsZVN0cmVhbU9wdGlvbnMsXG4gICAgICAgICAgYm9vdHN0cmFwTW9kdWxlczogW1xuICAgICAgICAgICAgLi4uKGluZGV4SHRtbCA/IFtiYXNlVVJMKGluZGV4SHRtbCldIDogW10pLFxuICAgICAgICAgICAgLi4uKHVzZXJPcHRpb25zLmNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucz8uYm9vdHN0cmFwTW9kdWxlcyA/P1xuICAgICAgICAgICAgICBbXSksXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgICAgLy8gQ3JlYXRlIENTUyBwcm9wcyBmb3IgZWFjaCBDU1MgZmlsZSAoc2FtZSBhcyBzZXJ2ZXItc3RhdGljKVxuICAgICAgICBjb25zdCB7IGNzc0ZpbGVzQnlQYWdlLCBnbG9iYWxDc3MgfSA9IHByb2Nlc3NDc3NGaWxlc0ZvclBhZ2VzKHtcbiAgICAgICAgICB1c2VyT3B0aW9ucyxcbiAgICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzLFxuICAgICAgICAgIHNlcnZlck1hbmlmZXN0LFxuICAgICAgICAgIHN0YXRpY01hbmlmZXN0LFxuICAgICAgICAgIGJ1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LFxuICAgICAgICAgIGxvZ2dlcixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IFtyb3V0ZSwgY3NzTWFwXSBvZiBjc3NGaWxlc0J5UGFnZS5lbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICBgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFJvdXRlICR7cm91dGV9OiAke2Nzc01hcC5zaXplfSBDU1MgZmlsZXNgXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgY3NzTWFwLmVudHJpZXMoKSkge1xuICAgICAgICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICBgW3JlYWN0LXN0YXRpYy1jbGllbnRdICAgQ1NTIGZpbGU6ICR7a2V5fSAtPiAke3ZhbHVlLmFzfSAoJHtcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmNoaWxkcmVuID8gXCJpbmxpbmVcIiA6IFwibGlua1wiXG4gICAgICAgICAgICAgICAgfSlgXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgcm91dGVzID0gQXJyYXkuZnJvbShcbiAgICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5rZXlzKClcbiAgICAgICAgKSBhcyBzdHJpbmdbXTtcblxuICAgICAgICAvLyBJZiBubyBwYWdlcyB0byBnZW5lcmF0ZSwgc2tpcCBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICBpZiAocm91dGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/LmluZm8oXG4gICAgICAgICAgICAgIFwiW3JlYWN0LXN0YXRpYy1jbGllbnRdIE5vIHBhZ2VzIHRvIGdlbmVyYXRlLCBza2lwcGluZyBzdGF0aWMgZ2VuZXJhdGlvblwiXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVc2UgdGhlIHN0YXRpYyBtYW5pZmVzdCB0byBlbnN1cmUgY29uc2lzdGVudCBtb2R1bGUgSURzIGJldHdlZW4gUlNDIHN0cmVhbSBhbmQgY2xpZW50IGJ1aWxkXG4gICAgICAgIC8vIFRoZSBzdGF0aWMgbWFuaWZlc3QgY29udGFpbnMgdGhlIGNvcnJlY3QgaGFzaGVzIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIGJvdGggYnVpbGRzXG4gICAgICAgIC8vIChzdGF0aWNNYW5pZmVzdCBhbHJlYWR5IGxvYWRlZCBhYm92ZSlcblxuICAgICAgICAvLyBDcmVhdGUgYSBidWlsZCBsb2FkZXIgZm9yIGNsaWVudCBtb2RlIChyZXVzZSBzZXJ2ZXIncyBzb3BoaXN0aWNhdGVkIGxvYWRlcilcbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBDcmVhdGluZyBidWlsZCBsb2FkZXJgKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBidWlsZExvYWRlciA9IGNyZWF0ZUJ1aWxkTG9hZGVyKCk7XG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gQnVpbGQgbG9hZGVyIGNyZWF0ZWRgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENyZWF0ZSBhbiBSU0Mgd29ya2VyIGZvciBnZW5lcmF0aW5nIFJTQyBjb250ZW50XG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICAgICAgYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBDcmVhdGluZyBSU0Mgd29ya2VyIHdpdGggcGF0aDogJHt1c2VyT3B0aW9ucy5yc2NXb3JrZXJQYXRofWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd29ya2VyU3RhcnRUaW1lID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgICAgIGxldCByc2NXb3JrZXJSZXN1bHQ7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcnNjV29ya2VyUmVzdWx0ID0gYXdhaXQgY3JlYXRlV29ya2VyKHtcbiAgICAgICAgICAgIHByb2plY3RSb290OiB1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCxcbiAgICAgICAgICAgIHdvcmtlclBhdGg6IHVzZXJPcHRpb25zLnJzY1dvcmtlclBhdGgsXG4gICAgICAgICAgICBjdXJyZW50Q29uZGl0aW9uOiBcInJlYWN0LWNsaWVudFwiLFxuICAgICAgICAgICAgcmV2ZXJzZUNvbmRpdGlvbjogXCJyZWFjdC1zZXJ2ZXJcIixcbiAgICAgICAgICAgIG1heExpc3RlbmVyczogTWF0aC5tYXgocm91dGVzLmxlbmd0aCAqIDMsIDEwKSwgLy8gQWNjb3VudCBmb3IgbXVsdGlwbGUgbGlzdGVuZXJzIHBlciByb3V0ZVxuICAgICAgICAgICAgZW52UHJlZml4OiBlbnZQcmVmaXhGcm9tQ29uZmlnKHJlc29sdmVkQ29uZmlnIGFzIGFueSksXG4gICAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICAgIHZlcmJvc2U6IHVzZXJPcHRpb25zLnZlcmJvc2UsXG4gICAgICAgICAgICBtb2RlOiBnZXROb2RlRW52KCksXG4gICAgICAgICAgICB3b3JrZXJEYXRhOiB7XG4gICAgICAgICAgICAgIHVzZXJPcHRpb25zOiBzZXJpYWxpemVkT3B0aW9ucyh1c2VyT3B0aW9ucywgYXV0b0Rpc2NvdmVyZWRGaWxlcyksXG4gICAgICAgICAgICAgIHJlc29sdmVkQ29uZmlnOiBzZXJpYWxpemVSZXNvbHZlZENvbmZpZyhyZXNvbHZlZENvbmZpZyBhcyBhbnkpLFxuICAgICAgICAgICAgICBjb25maWdFbnY6ICgoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmFsbGJhY2sgPSByZXNvbHZlZENvbmZpZ1xuICAgICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgICAgY29tbWFuZDogcmVzb2x2ZWRDb25maWcuY29tbWFuZCxcbiAgICAgICAgICAgICAgICAgICAgICBtb2RlOiByZXNvbHZlZENvbmZpZy5tb2RlLFxuICAgICAgICAgICAgICAgICAgICAgIGlzU3NyQnVpbGQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgIGlzUHJldmlldzogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpbmFsQ29uZmlnRW52ID0gY29uZmlnRW52IHx8IGZhbGxiYWNrO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZpbmFsQ29uZmlnRW52O1xuICAgICAgICAgICAgICB9KSgpLFxuICAgICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdDogc2VydmVyTWFuaWZlc3QgfHwge30sIC8vIFVzZSBzZXJ2ZXIgbWFuaWZlc3QgZm9yIHBhZ2UgY29tcG9uZW50IHJlc29sdXRpb25cbiAgICAgICAgICAgICAgYnVuZGxlOiBzdGF0aWNCdW5kbGUgfHwge30sIC8vIFVzZSBzdGF0aWMgYnVuZGxlIChjbGllbnQgYnVpbGQpIGZvciBwYWdlIGNvbXBvbmVudCByZXNvbHV0aW9uXG4gICAgICAgICAgICAgIHN0YXRpY0J1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LCAvLyBQYXNzIHN0YXRpYyBidW5kbGUgc2VwYXJhdGVseSBmb3IgcGF0aCByZXNvbHV0aW9uXG5cbiAgICAgICAgICAgICAgaWQ6IFwic3RhdGljLWNsaWVudC1yc2Mtd29ya2VyXCIsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoICh3b3JrZXJFcnJvcikge1xuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/LmVycm9yKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gRXJyb3IgY3JlYXRpbmcgUlNDIHdvcmtlcjogJHt3b3JrZXJFcnJvcn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgd29ya2VyRXJyb3I7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocnNjV29ya2VyUmVzdWx0LnR5cGUgIT09IFwic3VjY2Vzc1wiKSB7XG4gICAgICAgICAgY29uc3QgZXJyID0gcnNjV29ya2VyUmVzdWx0LmVycm9yID8/IG5ldyBFcnJvcihgRmFpbGVkIHRvIGNyZWF0ZSBSU0Mgd29ya2VyYCk7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uZXJyb3IoXG4gICAgICAgICAgICAgIGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gUlNDIHdvcmtlciBjcmVhdGlvbiBmYWlsZWQsIHRocm93aW5nIGVycm9yYCwgeyBlcnJvcjogZXJyIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJzY1dvcmtlciA9IHJzY1dvcmtlclJlc3VsdC53b3JrZXI7XG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gUlNDIHdvcmtlciBjcmVhdGVkIHN1Y2Nlc3NmdWxseWApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRW1pdCB3b3JrZXIgc3RhcnR1cCBtZXRyaWMgYWZ0ZXIgd29ya2VyIGlzIGNyZWF0ZWRcbiAgICAgICAgY29uc3Qgd29ya2VyU3RhcnR1cFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKSAtIHdvcmtlclN0YXJ0VGltZTtcbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLm9uTWV0cmljcykge1xuICAgICAgICAgIGNvbnN0IHdvcmtlclN0YXJ0dXBNZXRyaWMgPSBjcmVhdGVXb3JrZXJTdGFydHVwTWV0cmljcyh7XG4gICAgICAgICAgICByb3V0ZTogXCIvXCIsIC8vIFdvcmtlciBzdGFydHVwIGlzIGdsb2JhbCwgbm90IHJvdXRlLXNwZWNpZmljXG4gICAgICAgICAgICB3b3JrZXJUeXBlOiBcInJzY1wiLCAvLyBUaGlzIGlzIHRoZSBSU0Mgd29ya2VyIGZvciBjbGllbnQtc2lkZSBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgc3RhcnR1cFRpbWU6IHdvcmtlclN0YXJ0dXBUaW1lLFxuICAgICAgICAgICAgZnJvbU1haW5UaHJlYWQ6IHRydWUsXG4gICAgICAgICAgICBmcm9tUnNjV29ya2VyOiBmYWxzZSxcbiAgICAgICAgICAgIGZyb21IdG1sV29ya2VyOiBmYWxzZSxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgUlNDIHdvcmtlciBzdGFydHVwIGZvciBjbGllbnQtc2lkZSBzdGF0aWMgZ2VuZXJhdGlvbmAsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdXNlck9wdGlvbnMub25NZXRyaWNzKHdvcmtlclN0YXJ0dXBNZXRyaWMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVuZGVyIHBhZ2VzIHVzaW5nIGNsaWVudC1zaWRlIHJlbmRlcmVyIHdpdGggUlNDIHdvcmtlciBvbmx5XG4gICAgICAgIGNvbnN0IHsgb25FdmVudCwgb25NZXRyaWNzLCAuLi5oYW5kbGVyT3B0aW9ucyB9ID0gdXNlck9wdGlvbnM7XG5cbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBFeHRyYWN0ZWQgb25FdmVudDogJHt0eXBlb2Ygb25FdmVudH0sIHVzZXJPcHRpb25zLm9uRXZlbnQ6ICR7dHlwZW9mIHVzZXJPcHRpb25zLm9uRXZlbnR9YCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDYXB0dXJlIHNlcnZlciBidW5kbGUgZnJvbSBvbkV2ZW50IGlmIG5vdCBhbHJlYWR5IGNhcHR1cmVkXG4gICAgICAgIGlmICghc2VydmVyQnVuZGxlICYmIG9uRXZlbnQpIHtcbiAgICAgICAgICAvLyBDcmVhdGUgYSB0ZW1wb3JhcnkgZXZlbnQgaGFuZGxlciB0byBjYXB0dXJlIHRoZSBzZXJ2ZXIgYnVuZGxlXG4gICAgICAgICAgY29uc3Qgb3JpZ2luYWxPbkV2ZW50ID0gb25FdmVudDtcbiAgICAgICAgICBjb25zdCB0ZW1wT25FdmVudCA9IChldmVudDogYW55KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXZlbnQudHlwZSA9PT0gXCJidWlsZC53cml0ZUJ1bmRsZS5zZXJ2ZXJcIikge1xuICAgICAgICAgICAgICBzZXJ2ZXJCdW5kbGUgPSBldmVudC5kYXRhLmJ1bmRsZTtcbiAgICAgICAgICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICAgICAgICAgIFwiW3JlYWN0LXN0YXRpYy1jbGllbnRdIENhcHR1cmVkIHNlcnZlciBidW5kbGUgZnJvbSBidWlsZCBldmVudFwiXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBDYWxsIHRoZSBvcmlnaW5hbCBldmVudCBoYW5kbGVyXG4gICAgICAgICAgICBvcmlnaW5hbE9uRXZlbnQoZXZlbnQpO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICAvLyBSZXBsYWNlIHRoZSBvbkV2ZW50IHRlbXBvcmFyaWx5IHRvIGNhcHR1cmUgdGhlIHNlcnZlciBidW5kbGVcbiAgICAgICAgICB1c2VyT3B0aW9ucy5vbkV2ZW50ID0gdGVtcE9uRXZlbnQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFbWl0IHRoZSBzdGF0aWMgc2l0ZSBnZW5lcmF0aW9uIHN0YXJ0IGV2ZW50XG4gICAgICAgIC8vIFVzZSB0aGUgZXh0cmFjdGVkIG9uRXZlbnQgaWYgYXZhaWxhYmxlLCBvdGhlcndpc2UgZmFsbCBiYWNrIHRvIHVzZXJPcHRpb25zLm9uRXZlbnRcbiAgICAgICAgY29uc3QgZXZlbnRIYW5kbGVyID0gb25FdmVudCB8fCB1c2VyT3B0aW9ucy5vbkV2ZW50O1xuICAgICAgICBpZiAodHlwZW9mIGV2ZW50SGFuZGxlciA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEVtaXR0aW5nIGJ1aWxkLnNzZy5zdGFydCBldmVudGApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgciA9IGV2ZW50SGFuZGxlcih7XG4gICAgICAgICAgICAgIHR5cGU6IFwiYnVpbGQuc3NnLnN0YXJ0XCIsXG4gICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXAua2V5cygpID8/IFtdKSxcbiAgICAgICAgICAgICAgICBvcHRpb25zOiBudWxsIGFzIGFueSwgLy8gTm8gc3BlY2lmaWMgcm9sbHVwIG91dHB1dCBvcHRpb25zIGZvciBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgICAgIGJ1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAociAhPSBudWxsICYmIHR5cGVvZiByID09PSBcIm9iamVjdFwiICYmIFwidGhlblwiIGluIHIpIHtcbiAgICAgICAgICAgICAgYXdhaXQgKHIgYXMgUHJvbWlzZTxhbnk+KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgY29uc3QgZXZlbnRQYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICAgIHBhbmljVGhyZXNob2xkOiB1c2VyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgICAgICAgICAgY29udGV4dDogXCJvbkV2ZW50KGJ1aWxkLnNzZy5zdGFydClcIixcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGV2ZW50UGFuaWNFcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgICAgIHRocm93IGV2ZW50UGFuaWNFcnJvcjsgLy8gUmUtdGhyb3cgdG8gYWJvcnQgdGhlIGJ1aWxkXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/Lndhcm4oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBObyBvbkV2ZW50IGhhbmRsZXIgYXZhaWxhYmxlIHRvIGVtaXQgYnVpbGQuc3NnLnN0YXJ0YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZW5kZXJQYWdlc0dlbmVyYXRvciA9IHJlbmRlclBhZ2VzQmF0Y2hlZChcbiAgICAgICAgICByb3V0ZXMsXG4gICAgICAgICAge1xuICAgICAgICAgICAgLi4uaGFuZGxlck9wdGlvbnMsIC8vIFVzZSB0aGUgY2xlYW4gb3B0aW9ucyBpbnN0ZWFkIG9mIHRoZSBvcmlnaW5hbCBoYW5kbGVyT3B0aW9uc1xuICAgICAgICAgICAgd29ya2VyOiByc2NXb3JrZXIsIC8vIFBhc3MgdGhlIFJTQyB3b3JrZXIgZm9yIFJTQyByZW5kZXJpbmcgb25seVxuICAgICAgICAgICAgcnNjV29ya2VyOiByc2NXb3JrZXIsIC8vIFBhc3MgdGhlIFJTQyB3b3JrZXIgZm9yIFJTQyByZW5kZXJpbmcgb25seVxuICAgICAgICAgICAgbG9hZGVyOiBidWlsZExvYWRlciwgLy8gVXNlIHByb3BlciBidWlsZCBsb2FkZXIgaW5zdGVhZCBvZiBuby1vcFxuICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzOiBhdXRvRGlzY292ZXJlZEZpbGVzLFxuICAgICAgICAgICAgY3NzRmlsZXNCeVBhZ2U6IGNzc0ZpbGVzQnlQYWdlLCAvLyBQYXNzIENTUyBmaWxlcyBieSBwYWdlXG4gICAgICAgICAgICBzZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnM6IHNlcnZlclBpcGVhYmxlU3RyZWFtT3B0aW9ucywgLy8gUGFzcyBzZXJ2ZXIgb3B0aW9ucyB0byBSU0Mgd29ya2VyXG4gICAgICAgICAgICBjbGllbnRQaXBlYWJsZVN0cmVhbU9wdGlvbnM6IGNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucywgLy8gUGFzcyBjbGllbnQgb3B0aW9ucyB0byBSU0Mgd29ya2VyXG4gICAgICAgICAgICBnbG9iYWxDc3M6IGdsb2JhbENzcywgLy8gUGFzcyBnbG9iYWwgQ1NTXG4gICAgICAgICAgICBtYW5pZmVzdDogc2VydmVyTWFuaWZlc3QgfHwge30sIC8vIFNlcnZlciBtYW5pZmVzdCBmb3IgUlNDIHdvcmtlclxuICAgICAgICAgICAgc3RhdGljTWFuaWZlc3Q6IHN0YXRpY01hbmlmZXN0LCAvLyBTdGF0aWMgbWFuaWZlc3QgZm9yIGNvbnNpc3RlbnQgbW9kdWxlIElEc1xuICAgICAgICAgICAgb25FdmVudDogb25FdmVudCxcbiAgICAgICAgICAgIG9uTWV0cmljczogb25NZXRyaWNzLCAvLyBQYXNzIHRocm91Z2ggdGhlIG9uTWV0cmljcyBjYWxsYmFjayAobWV0cmljIHdhdGNoZXIpXG4gICAgICAgICAgfSxcbiAgICAgICAgICByZW5kZXJQYWdlXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUHJvY2VzcyB0aGUgcmVuZGVyZWQgcGFnZXNcbiAgICAgICAgbGV0IGZpbmFsUmVzdWx0OiBhbnkgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgZm9yIGF3YWl0IChjb25zdCByZXN1bHQgb2YgcmVuZGVyUGFnZXNHZW5lcmF0b3IpIHtcbiAgICAgICAgICAgIGlmIChyZXN1bHQudHlwZSA9PT0gXCJlcnJvclwiKSB7XG4gICAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyPy5lcnJvcihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFJlbmRlciBlcnJvcjogJHtyZXN1bHQuZXJyb3J9YCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdGhyb3cgcmVzdWx0LmVycm9yO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gSGFuZGxlIGZhaWxlZCByb3V0ZXMgYmFzZWQgb24gcGFuaWMgdGhyZXNob2xkXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgcmVzdWx0LnR5cGUgPT09IFwic3VjY2Vzc1wiICYmXG4gICAgICAgICAgICByZXN1bHQuZmFpbGVkUm91dGVzICYmXG4gICAgICAgICAgICByZXN1bHQuZmFpbGVkUm91dGVzLnNpemUgPiAwXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBVc2UgY2VudHJhbGl6ZWQgcGFuaWMgdGhyZXNob2xkIGxvZ2ljIChzYW1lIGFzIHNlcnZlciBwbHVnaW4pXG4gICAgICAgICAgICBjb25zdCBmaXJzdEVycm9yID0gcmVzdWx0LmZhaWxlZFJvdXRlcy52YWx1ZXMoKS5uZXh0KCkudmFsdWU7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIGZpcnN0RXJyb3IgIT0gbnVsbCAmJlxuICAgICAgICAgICAgICBzaG91bGRDYXVzZVBhbmljKGZpcnN0RXJyb3IsIHtcbiAgICAgICAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgY2F1c2UgYSBwYW5pYywgdGhyb3cgdGhlIGVycm9yXG4gICAgICAgICAgICAgIHRocm93IGZpcnN0RXJyb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBGb3Igb3RoZXIgcGFuaWMgdGhyZXNob2xkcywgbG9nIHdhcm5pbmdzIGJ1dCBjb250aW51ZVxuICAgICAgICAgICAgZm9yIChjb25zdCBbcm91dGUsIGVycm9yXSBvZiByZXN1bHQuZmFpbGVkUm91dGVzKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVyciA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IHRvRXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICBjbG9zZUJ1bmRsZUNvbnRleHQud2FybihcbiAgICAgICAgICAgICAgICBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICBcIkZhaWxlZCB0byByZW5kZXIgcm91dGU6IFwiICtcbiAgICAgICAgICAgICAgICAgICAgcm91dGUgK1xuICAgICAgICAgICAgICAgICAgICBcIlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgZXJyLm1lc3NhZ2UgK1xuICAgICAgICAgICAgICAgICAgICBcIlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgZXJyLnN0YWNrLFxuICAgICAgICAgICAgICAgICAgeyBjYXVzZTogZXJyIH1cbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgICBmaW5hbFJlc3VsdCA9IHJlc3VsdDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKHJlbmRlckVycm9yKSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uZXJyb3IoYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBFcnJvciBkdXJpbmcgcmVuZGVyUGFnZXM6ICR7cmVuZGVyRXJyb3J9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IHJlbmRlckVycm9yO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFmaW5hbFJlc3VsdCkge1xuICAgICAgICAgIGNvbnN0IGVycm9yTXNnID0gXCJObyByZW5kZXIgcmVzdWx0IHByb2R1Y2VkXCI7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uZXJyb3IoYFtyZWFjdC1zdGF0aWMtY2xpZW50XSAke2Vycm9yTXNnfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3JNc2cpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBSZW5kZXIgY29tcGxldGVkOiAke2ZpbmFsUmVzdWx0LmNvbXBsZXRlZFJvdXRlcy5zaXplfSBwYWdlcywgJHtmaW5hbFJlc3VsdC5mYWlsZWRSb3V0ZXM/LnNpemUgfHwgMH0gZmFpbGVkYCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBGaWxlIHdyaXRlcyBhcmUgaGFuZGxlZCBieSByZW5kZXJQYWdlcywgbm8gbmVlZCB0byBkbyB0aGVtIGhlcmVcblxuICAgICAgICAvLyBDYWxjdWxhdGUgZHVyYXRpb24gZnJvbSB0aW1pbmdcbiAgICAgICAgY29uc3QgZHVyYXRpb24gPSBNYXRoLnJvdW5kKFxuICAgICAgICAgIHBlcmZvcm1hbmNlLm5vdygpIC0gKHRpbWluZy5yZW5kZXJTdGFydCB8fCB0aW1pbmcuc3RhcnQpXG4gICAgICAgICk7XG5cbiAgICAgICAgY2xvc2VCdW5kbGVDb250ZXh0LmluZm8oXG4gICAgICAgICAgYFJlbmRlcmVkICR7ZmluYWxSZXN1bHQuY29tcGxldGVkUm91dGVzLnNpemV9IHBhZ2VzIGluICR7ZHVyYXRpb259bXNgXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKHByb2Nlc3MuZW52W1wiTk9ERV9FTlZcIl0gIT09IFwicHJvZHVjdGlvblwiKSB7XG4gICAgICAgICAgY2xvc2VCdW5kbGVDb250ZXh0Lndhcm4oXG4gICAgICAgICAgICBgVEhJUyBCVUlMRCBJUyBOT1QgSU5URU5ERUQgRk9SIFBST0RVQ1RJT04gKCR7cHJvY2Vzcy5lbnZbXCJOT0RFX0VOVlwiXX0pYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgdGltaW5nXG4gICAgICAgIHRpbWluZy5yZW5kZXIgPVxuICAgICAgICAgIHBlcmZvcm1hbmNlLm5vdygpIC0gKHRpbWluZy5yZW5kZXJTdGFydCA/PyB0aW1pbmcuc3RhcnQpO1xuXG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKFwiW3JlYWN0LXN0YXRpYy1jbGllbnRdIFN0YXRpYyBnZW5lcmF0aW9uIGNvbXBsZXRlZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVtaXQgdGhlIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gY29tcGxldGlvbiBldmVudCBvbmNlXG4gICAgICAgIGlmICh0eXBlb2YgdXNlck9wdGlvbnMub25FdmVudCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHIgPSB1c2VyT3B0aW9ucy5vbkV2ZW50KHtcbiAgICAgICAgICAgICAgdHlwZTogXCJidWlsZC5zc2cuZW5kXCIsXG4gICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXAua2V5cygpID8/IFtdKSxcbiAgICAgICAgICAgICAgICBvcHRpb25zOiBudWxsIGFzIGFueSwgLy8gTm8gc3BlY2lmaWMgcm9sbHVwIG91dHB1dCBvcHRpb25zIGZvciBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgICAgIGJ1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAociAhPSBudWxsICYmIHR5cGVvZiByID09PSBcIm9iamVjdFwiICYmIFwidGhlblwiIGluIHIpIHtcbiAgICAgICAgICAgICAgYXdhaXQgKHIgYXMgUHJvbWlzZTxhbnk+KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgY29uc3QgZXZlbnRQYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICAgIHBhbmljVGhyZXNob2xkOiB1c2VyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgICAgICAgICAgY29udGV4dDogXCJvbkV2ZW50KGJ1aWxkLnNzZy5lbmQpXCIsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChldmVudFBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgICAgICB0aHJvdyBldmVudFBhbmljRXJyb3I7IC8vIFJlLXRocm93IHRvIGFib3J0IHRoZSBidWlsZFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc3QgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICBjb250ZXh0OiBcInJlYWN0LXN0YXRpYy1jbGllbnRcIixcbiAgICAgICAgICBsb2dnZXIsXG4gICAgICAgICAgcGFuaWNUaHJlc2hvbGQ6IHVzZXJPcHRpb25zLnBhbmljVGhyZXNob2xkLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBFbnN1cmUgZ3JhY2VmdWwgc2h1dGRvd24gb24gZXJyb3JcbiAgICAgICAgaWYgKHJzY1dvcmtlcikge1xuICAgICAgICAgIGNvbnN0IHdvcmtlclRvQ2xlYW51cCA9IHJzY1dvcmtlcjtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gVXNlIGdyYWNlZnVsIHNodXRkb3duIHByb3RvY29sIGV2ZW4gb24gZXJyb3JcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgICAgICAgICAgIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICB3b3JrZXJUb0NsZWFudXAucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICAgICAgICB3b3JrZXJUb0NsZWFudXAudGVybWluYXRlKCk7XG4gICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgfSwgMTAwMCk7IC8vIDEgc2Vjb25kIHRpbWVvdXQgZm9yIGdyYWNlZnVsIHNodXRkb3duXG5cbiAgICAgICAgICAgICAgICBjb25zdCBtZXNzYWdlSGFuZGxlciA9IChtZXNzYWdlOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmIChtZXNzYWdlLnR5cGUgPT09IFwiU0hVVERPV05fQ09NUExFVEVcIikge1xuICAgICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgICAgICAgICAgICAgICAgd29ya2VyVG9DbGVhbnVwLnJlbW92ZUxpc3RlbmVyKFwibWVzc2FnZVwiLCBtZXNzYWdlSGFuZGxlcik7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHdvcmtlclRvQ2xlYW51cC5vbihcIm1lc3NhZ2VcIiwgbWVzc2FnZUhhbmRsZXIpO1xuICAgICAgICAgICAgICAgIHdvcmtlclRvQ2xlYW51cC5wb3N0TWVzc2FnZSh7IHR5cGU6IFwiU0hVVERPV05cIiB9KTtcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICAgIHJzY1dvcmtlciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB9IGNhdGNoIChjbGVhbnVwRXJyb3IpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKGBGYWlsZWQgdG8gY2xlYW51cCB3b3JrZXIgb24gZXJyb3I6ICR7Y2xlYW51cEVycm9yfWApO1xuICAgICAgICAgICAgLy8gRm9yY2UgdGVybWluYXRlIGlmIGdyYWNlZnVsIHNodXRkb3duIGZhaWxzXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICB3b3JrZXJUb0NsZWFudXAucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICAgIHdvcmtlclRvQ2xlYW51cC50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKHRlcm1pbmF0ZUVycm9yKSB7XG4gICAgICAgICAgICAgIC8vIElnbm9yZSB0ZXJtaW5hdGlvbiBlcnJvcnNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJzY1dvcmtlciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGFuaWNFcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgLy8gRW5zdXJlIHdlIGhhdmUgYSBwcm9wZXIgRXJyb3Igb2JqZWN0IHRoYXQgY2FuIGhhdmUgcHJvcGVydGllcyBzZXQgb24gaXRcbiAgICAgICAgICBjb25zdCBlcnJvclRvVGhyb3cgPVxuICAgICAgICAgICAgcGFuaWNFcnJvciBpbnN0YW5jZW9mIEVycm9yXG4gICAgICAgICAgICAgID8gcGFuaWNFcnJvclxuICAgICAgICAgICAgICA6IG5ldyBFcnJvcihTdHJpbmcocGFuaWNFcnJvcikpO1xuXG4gICAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IEVycm9yIG9iamVjdCB0byBhdm9pZCB0aGUgXCJjb2RlXCIgcHJvcGVydHkgaXNzdWVcbiAgICAgICAgICBjb25zdCBmaW5hbEVycm9yID0gbmV3IEVycm9yKGVycm9yVG9UaHJvdy5tZXNzYWdlKTtcbiAgICAgICAgICBmaW5hbEVycm9yLnN0YWNrID0gZXJyb3JUb1Rocm93LnN0YWNrO1xuICAgICAgICAgIGZpbmFsRXJyb3IuY2F1c2UgPSBlcnJvclRvVGhyb3cuY2F1c2U7XG5cbiAgICAgICAgICAvLyBDb3B5IGFueSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgdGhhdCBtaWdodCBiZSBuZWVkZWRcbiAgICAgICAgICBpZiAoZXJyb3JUb1Rocm93Lm5hbWUpIGZpbmFsRXJyb3IubmFtZSA9IGVycm9yVG9UaHJvdy5uYW1lO1xuXG4gICAgICAgIHRocm93IGZpbmFsRXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIC8vIEdyYWNlZnVsIHdvcmtlciBzaHV0ZG93biDigJQgcnVucyBvbiBib3RoIHN1Y2Nlc3MgYW5kIGVycm9yIHBhdGhzXG4gICAgICAgIGlmIChyc2NXb3JrZXIpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgICAgICAgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoXCJXb3JrZXIgc2h1dGRvd24gdGltZW91dFwiKSk7XG4gICAgICAgICAgICAgICAgfSwgdXNlck9wdGlvbnMud29ya2VyU2h1dGRvd25UaW1lb3V0KTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGJhY2t1cFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoXCJXb3JrZXIgc2h1dGRvd24gYmFja3VwIHRpbWVvdXRcIikpO1xuICAgICAgICAgICAgICAgIH0sIE1hdGguZmxvb3IodXNlck9wdGlvbnMud29ya2VyU2h1dGRvd25UaW1lb3V0ICogMC42KSk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBzaHV0ZG93bk1lc3NhZ2VIYW5kbGVyID0gKG1lc3NhZ2U6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJTSFVURE9XTl9DT01QTEVURVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KGJhY2t1cFRpbWVvdXQpO1xuICAgICAgICAgICAgICAgICAgICByc2NXb3JrZXI/LnJlbW92ZUxpc3RlbmVyKFxuICAgICAgICAgICAgICAgICAgICAgIFwibWVzc2FnZVwiLFxuICAgICAgICAgICAgICAgICAgICAgIHNodXRkb3duTWVzc2FnZUhhbmRsZXJcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgcnNjV29ya2VyPy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICByc2NXb3JrZXI/Lm9uKFwibWVzc2FnZVwiLCBzaHV0ZG93bk1lc3NhZ2VIYW5kbGVyKTtcbiAgICAgICAgICAgICAgICByc2NXb3JrZXI/LnBvc3RNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAgIHR5cGU6IFwiU0hVVERPV05cIixcbiAgICAgICAgICAgICAgICAgIGlkOiBcIipcIixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIC8vIFNodXRkb3duIHByb3RvY29sIGZhaWxlZCDigJQgZm9yY2UgdGVybWluYXRlIGJlbG93XG4gICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGlmIChyc2NXb3JrZXIpIHtcbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAocnNjV29ya2VyIGFzIFdvcmtlcikucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICAgICAgKHJzY1dvcmtlciBhcyBXb3JrZXIpLnRlcm1pbmF0ZSgpO1xuICAgICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAvLyBJZ25vcmUgdGVybWluYXRpb24gZXJyb3JzXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgcnNjV29ya2VyID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlc2V0IGFueSBjYWNoZWQgc3RhdGUgdG8gcHJldmVudCBpc3N1ZXMgaW4gc3Vic2VxdWVudCBidWlsZHNcbiAgICAgICAgYXV0b0Rpc2NvdmVyZWRGaWxlcyA9IG51bGw7XG4gICAgICAgIHNlcnZlck1hbmlmZXN0ID0gdW5kZWZpbmVkO1xuICAgICAgfVxuXG4gICAgICB9KTsgLy8gZW5kIGRlZmVyU3RhdGljR2VuZXJhdGlvblxuICAgIH0sXG4gIH07XG59O1xuIl0sIm5hbWVzIjpbImpvaW4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQWdFQSxvQkFBcUIsRUFBQTtBQWdCUixNQUFBLGlCQUFBLEdBQWtDLFNBQVMsa0JBQUEsQ0FDdEQsT0FDQSxFQUFBO0FBQ0EsRUFBSSxJQUFBLE1BQUE7QUFDSixFQUFBLElBQUksbUJBQWtELEdBQUEsSUFBQTtBQUN0RCxFQUFBLElBQUksU0FBZ0MsR0FBQSxNQUFBO0FBQ3BDLEVBQUEsSUFBSSxjQUF3QyxHQUFBLElBQUE7QUFDNUMsRUFBQSxJQUFJLGNBQXVDLEdBQUEsTUFBQTtBQUMzQyxFQUFBLElBQUksWUFBeUMsR0FBQSxNQUFBO0FBQzdDLEVBQUEsSUFBSSxZQUF5QyxHQUFBLE1BQUE7QUFFN0MsRUFBSSxJQUFBLFNBQUE7QUFDSixFQUFBLE1BQU0sTUFBc0IsR0FBQTtBQUFBLElBQzFCLEtBQUEsRUFBTyxZQUFZLEdBQUks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
|