vite-plugin-react-server 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +48 -313
  2. package/dist/package.json +123 -13
  3. package/dist/plugin/bundle/deferredStaticGeneration.js +14 -39
  4. package/dist/plugin/bundle/manifests.js +30 -48
  5. package/dist/plugin/config/autoDiscover/resolveAutoDiscover.d.ts.map +1 -1
  6. package/dist/plugin/config/autoDiscover/resolveAutoDiscover.js +4 -1
  7. package/dist/plugin/config/envPrefixFromConfig.js +12 -7
  8. package/dist/plugin/config/getCondition.d.ts.map +1 -1
  9. package/dist/plugin/config/getCondition.js +7 -5
  10. package/dist/plugin/dev-server/configureReactServer.server.d.ts.map +1 -1
  11. package/dist/plugin/dev-server/configureReactServer.server.js +5 -8
  12. package/dist/plugin/dev-server/plugin.client.d.ts.map +1 -1
  13. package/dist/plugin/dev-server/plugin.client.js +2 -1
  14. package/dist/plugin/dev-server/plugin.server.d.ts.map +1 -1
  15. package/dist/plugin/dev-server/plugin.server.js +2 -36
  16. package/dist/plugin/dev-server/virtualRscHmrPlugin.js +23 -23
  17. package/dist/plugin/environments/createBuildEventPlugin.js +88 -98
  18. package/dist/plugin/environments/createEnvironmentPlugin.js +222 -250
  19. package/dist/plugin/error/index.d.ts +1 -2
  20. package/dist/plugin/error/index.d.ts.map +1 -1
  21. package/dist/plugin/error/index.js +2 -3
  22. package/dist/plugin/error/panicThresholdHandler.js +14 -3
  23. package/dist/plugin/error/setupGlobalErrorHandler.d.ts.map +1 -1
  24. package/dist/plugin/error/setupGlobalErrorHandler.js +23 -16
  25. package/dist/plugin/helpers/createRscRenderHelpers.d.ts +0 -5
  26. package/dist/plugin/helpers/createRscRenderHelpers.d.ts.map +1 -1
  27. package/dist/plugin/helpers/createRscRenderHelpers.js +32 -55
  28. package/dist/plugin/helpers/createSharedLoader.d.ts.map +1 -1
  29. package/dist/plugin/helpers/createSharedLoader.js +4 -2
  30. package/dist/plugin/helpers/headlessStreamReuseHandler.js +30 -22
  31. package/dist/plugin/helpers/headlessStreamState.d.ts +0 -38
  32. package/dist/plugin/helpers/headlessStreamState.d.ts.map +1 -1
  33. package/dist/plugin/helpers/headlessStreamState.js +15 -76
  34. package/dist/plugin/helpers/index.d.ts +0 -3
  35. package/dist/plugin/helpers/index.d.ts.map +1 -1
  36. package/dist/plugin/helpers/index.js +1 -4
  37. package/dist/plugin/helpers/requestInfo.d.ts.map +1 -1
  38. package/dist/plugin/helpers/requestInfo.js +3 -3
  39. package/dist/plugin/helpers/resolveComponent.d.ts.map +1 -1
  40. package/dist/plugin/helpers/resolveComponent.js +4 -2
  41. package/dist/plugin/helpers/workerCleanup.d.ts +1 -12
  42. package/dist/plugin/helpers/workerCleanup.d.ts.map +1 -1
  43. package/dist/plugin/helpers/workerCleanup.js +1 -1
  44. package/dist/plugin/index.client.d.ts +5 -0
  45. package/dist/plugin/index.client.d.ts.map +1 -0
  46. package/dist/plugin/index.client.js +4 -0
  47. package/dist/plugin/index.d.ts +4 -3
  48. package/dist/plugin/index.d.ts.map +1 -1
  49. package/dist/plugin/index.js +10 -5
  50. package/dist/plugin/index.server.d.ts +5 -0
  51. package/dist/plugin/index.server.d.ts.map +1 -0
  52. package/dist/plugin/index.server.js +4 -0
  53. package/dist/plugin/loader/directives/index.d.ts +0 -1
  54. package/dist/plugin/loader/directives/index.d.ts.map +1 -1
  55. package/dist/plugin/loader/directives/index.js +1 -2
  56. package/dist/plugin/metrics/createWorkerStartupMetrics.js +31 -13
  57. package/dist/plugin/orchestrator/createPluginOrchestrator.client.js +41 -38
  58. package/dist/plugin/orchestrator/createPluginOrchestrator.server.js +43 -46
  59. package/dist/plugin/plugin.client.js +2 -2
  60. package/dist/plugin/plugin.server.js +2 -2
  61. package/dist/plugin/react-static/createBuildLoader.client.js +12 -6
  62. package/dist/plugin/react-static/createBuildLoader.server.js +255 -235
  63. package/dist/plugin/react-static/plugin.client.js +684 -770
  64. package/dist/plugin/react-static/plugin.server.js +517 -603
  65. package/dist/plugin/react-static/processCssFilesForPages.js +103 -88
  66. package/dist/plugin/react-static/renderPage.client.js +455 -529
  67. package/dist/plugin/react-static/renderPage.server.js +485 -508
  68. package/dist/plugin/react-static/renderPagesBatched.js +277 -275
  69. package/dist/plugin/react-static/rscToHtmlStream.client.js +48 -29
  70. package/dist/plugin/react-static/rscToHtmlStream.server.js +62 -37
  71. package/dist/plugin/react-static/temporaryReferences.server.js +11 -2
  72. package/dist/plugin/stream/createMainThreadHandlers.js +40 -31
  73. package/dist/plugin/stream/renderRscStream.server.d.ts.map +1 -1
  74. package/dist/plugin/stream/renderRscStream.server.js +127 -144
  75. package/dist/plugin/transformer/createTransformerPlugin.js +226 -265
  76. package/dist/plugin/utils/checkReactVersion.d.ts +7 -0
  77. package/dist/plugin/utils/checkReactVersion.d.ts.map +1 -0
  78. package/dist/plugin/utils/checkReactVersion.js +23 -0
  79. package/dist/plugin/utils/envUrls.node.js +12 -11
  80. package/dist/plugin/vendor/vendor-alias.js +84 -114
  81. package/dist/plugin/vendor/vendor.client.d.ts.map +1 -1
  82. package/dist/plugin/vendor/vendor.client.js +1 -3
  83. package/dist/plugin/worker/rsc/handleRscRender.d.ts.map +1 -1
  84. package/dist/plugin/worker/rsc/handleRscRender.js +3 -1
  85. package/dist/tsconfig.tsbuildinfo +1 -1
  86. package/package.json +123 -13
  87. package/plugin/config/autoDiscover/resolveAutoDiscover.ts +4 -0
  88. package/plugin/config/getCondition.ts +6 -4
  89. package/plugin/dev-server/configureReactServer.server.ts +7 -10
  90. package/plugin/dev-server/plugin.client.ts +2 -0
  91. package/plugin/dev-server/plugin.server.ts +2 -49
  92. package/plugin/error/index.ts +1 -2
  93. package/plugin/error/setupGlobalErrorHandler.ts +24 -25
  94. package/plugin/helpers/createRscRenderHelpers.ts +0 -29
  95. package/plugin/helpers/createSharedLoader.ts +6 -1
  96. package/plugin/helpers/headlessStreamState.ts +0 -69
  97. package/plugin/helpers/index.ts +0 -3
  98. package/plugin/helpers/requestInfo.ts +1 -2
  99. package/plugin/helpers/resolveComponent.ts +6 -1
  100. package/plugin/helpers/workerCleanup.ts +1 -38
  101. package/plugin/index.client.ts +4 -0
  102. package/plugin/index.server.ts +4 -0
  103. package/plugin/index.ts +12 -5
  104. package/plugin/loader/directives/index.ts +0 -1
  105. package/plugin/plugin.client.ts +1 -1
  106. package/plugin/plugin.server.ts +1 -1
  107. package/plugin/stream/renderRscStream.server.ts +3 -0
  108. package/plugin/transformer/README.md +1 -1
  109. package/plugin/utils/checkReactVersion.ts +28 -0
  110. package/plugin/vendor/vendor.client.ts +0 -2
  111. package/plugin/worker/html/README.md +1 -1
  112. package/plugin/worker/rsc/README.md +1 -1
  113. package/plugin/worker/rsc/handleRscRender.ts +2 -0
  114. package/scripts/generate-toc.mjs +27 -294
  115. package/dist/plugin/error/assertPanic.d.ts +0 -2
  116. package/dist/plugin/error/assertPanic.d.ts.map +0 -1
  117. package/dist/plugin/error/assertPanic.js +0 -15
  118. package/dist/plugin/error/directiveError.d.ts +0 -13
  119. package/dist/plugin/error/directiveError.d.ts.map +0 -1
  120. package/dist/plugin/error/directiveError.js +0 -21
  121. package/dist/plugin/error/enhanceError.d.ts +0 -14
  122. package/dist/plugin/error/enhanceError.d.ts.map +0 -1
  123. package/dist/plugin/error/enhanceError.js +0 -24
  124. package/dist/plugin/helpers/createSafePageComponent.d.ts +0 -36
  125. package/dist/plugin/helpers/createSafePageComponent.d.ts.map +0 -1
  126. package/dist/plugin/helpers/createSafePageComponent.js +0 -50
  127. package/dist/plugin/helpers/moduleResolver.d.ts +0 -25
  128. package/dist/plugin/helpers/moduleResolver.d.ts.map +0 -1
  129. package/dist/plugin/helpers/moduleResolver.js +0 -64
  130. package/dist/plugin/helpers/stashReturnValue.d.ts +0 -3
  131. package/dist/plugin/helpers/stashReturnValue.d.ts.map +0 -1
  132. package/dist/plugin/helpers/stashReturnValue.js +0 -23
  133. package/dist/plugin/helpers/workerManager.d.ts +0 -5
  134. package/dist/plugin/helpers/workerManager.d.ts.map +0 -1
  135. package/dist/plugin/helpers/workerManager.js +0 -18
  136. package/dist/plugin/loader/directives/collectExportsFromModule.d.ts +0 -6
  137. package/dist/plugin/loader/directives/collectExportsFromModule.d.ts.map +0 -1
  138. package/dist/plugin/loader/directives/collectExportsFromModule.js +0 -24
  139. package/plugin/error/assertPanic.ts +0 -9
  140. package/plugin/error/directiveError.ts +0 -29
  141. package/plugin/error/enhanceError.ts +0 -41
  142. package/plugin/helpers/createSafePageComponent.ts +0 -64
  143. package/plugin/helpers/moduleResolver.ts +0 -91
  144. package/plugin/helpers/stashReturnValue.ts +0 -19
  145. package/plugin/helpers/workerManager.ts +0 -16
  146. package/plugin/loader/directives/collectExportsFromModule.ts +0 -25
@@ -1,533 +1,510 @@
1
1
  /**
2
- * renderPage.server.ts
3
- *
4
- * PURPOSE: Server-side static page rendering for React Server Components
5
- *
6
- * ARCHITECTURE OVERVIEW:
7
- *
8
- * SERVER-SIDE vs CLIENT-SIDE:
9
- * - Server-side: RSC generation in main thread, HTML generation in worker
10
- * - Client-side: RSC generation in worker, HTML generation in main thread
11
- *
12
- * FLOW:
13
- * 1. Create headless RSC stream (for .rsc file)
14
- * 2. Create full RSC stream (for HTML generation)
15
- * 3. Create HTML transform stream that converts RSC to HTML
16
- * 4. Both streams are piped to file writers
17
- *
18
- * SIMPLIFIED APPROACH:
19
- * This implementation follows the same simple pattern as the client side,
20
- * avoiding complex backpressure handling and race conditions.
2
+ * vite-plugin-react-server
3
+ * Copyright (c) Nico Brinkkemper
4
+ * MIT License
21
5
  */
22
- import { createRenderMetrics } from "../metrics/createRenderMetrics.js";
23
- import { routeToURL } from "../utils/routeToURL.js";
24
- import { handleError } from "../error/handleError.js";
25
- import { assertReactServer } from "../config/getCondition.js";
26
- import { renderRscStream } from "../stream/renderRscStream.server.js";
27
- import { createMainThreadHandlers } from "../stream/createMainThreadHandlers.js";
28
- import { createRscToHtmlStream } from "./rscToHtmlStream.server.js";
29
- import { resolveComponent } from "../helpers/resolveComponent.js";
30
- import { resolvePageAndProps } from "../helpers/resolvePageAndProps.js";
31
- import { Root as DefaultRoot } from "../components/root.js";
32
- import { Html as DefaultHtml } from "../components/html.js";
33
- import { createStreamMetrics } from "../metrics/createStreamMetrics.js";
34
- import { join } from "node:path";
35
- import { createHeadlessStreamState, trackHeadlessStreamError, hasHeadlessStreamError } from "../helpers/headlessStreamState.js";
36
- export const renderPage = async function* renderPage(handlerOptions) {
37
- // Ensure we're in the correct environment
38
- assertReactServer();
39
- // Create metrics upfront with proper types
40
- const baseDir = join(handlerOptions.build.outDir, handlerOptions.build.static);
41
- const routePath = handlerOptions.route.replace(/^\//, "");
42
- const htmlMetrics = createRenderMetrics({
43
- route: handlerOptions.route,
44
- type: "html",
45
- fromMainThread: false, // Server: HTML rendered in worker
46
- fromRscWorker: false,
47
- fromHtmlWorker: true,
48
- baseDir,
49
- routePath,
50
- fileName: handlerOptions.build.htmlOutputPath,
51
- outputPath: join(baseDir, routePath, handlerOptions.build.htmlOutputPath),
52
- });
53
- const rscFullMetrics = createRenderMetrics({
54
- route: handlerOptions.route,
55
- type: "rsc-full",
56
- fromMainThread: true, // Server: RSC rendered on main thread
57
- fromRscWorker: false,
58
- fromHtmlWorker: false,
59
- });
60
- const rscHeadlessMetrics = createRenderMetrics({
61
- route: handlerOptions.route,
62
- type: "rsc-headless",
63
- fromMainThread: true, // Server: RSC rendered on main thread
64
- fromRscWorker: false,
65
- fromHtmlWorker: false,
66
- baseDir,
67
- routePath,
68
- fileName: handlerOptions.build.rscOutputPath,
69
- outputPath: join(baseDir, routePath, handlerOptions.build.rscOutputPath),
70
- });
71
- // Declare variables outside try block
72
- let headlessRscHandler = null;
73
- let fullRscHandler = null;
74
- let htmlTransformStream = null;
75
- // Error tracking variables for headless stream
76
- let headlessStreamErrored = false;
77
- let headlessError = null;
78
- // Error tracking variables for HTML stream
79
- let htmlStreamErrored = false;
80
- let htmlStreamError = null;
81
- // Server-side stream reuse storage (similar to client-side headlessStreamElements)
82
- const headlessStreamState = createHeadlessStreamState();
83
- try {
84
- if (handlerOptions.verbose) {
85
- handlerOptions.logger?.info(`[renderPage.server] Server-side rendering for route: ${handlerOptions.route}`);
86
- }
87
- // Set URL if not provided
88
- if (!handlerOptions.url) {
89
- handlerOptions.url = routeToURL(handlerOptions.route, handlerOptions.moduleBaseURL, handlerOptions.build.rscOutputPath);
90
- }
91
- // Resolve components and props using the proper helper
92
- let PageComponent = null;
93
- let RootComponent = null;
94
- let HtmlComponent = null;
95
- let pageProps = {}; // Initialize as empty object - props function will populate it
96
- // Use resolvePageAndProps helper to properly load page and props
97
- if (handlerOptions.pagePath) {
98
- try {
99
- const pageAndPropsResult = await resolvePageAndProps({
100
- pagePath: handlerOptions.pagePath,
101
- pageExportName: handlerOptions.pageExportName,
102
- propsPath: handlerOptions.propsPath,
103
- propsExportName: handlerOptions.propsExportName,
104
- loader: handlerOptions.loader,
105
- verbose: handlerOptions.verbose,
106
- logger: handlerOptions.logger,
107
- route: handlerOptions.route,
108
- url: handlerOptions.url,
109
- moduleBaseURL: handlerOptions.moduleBaseURL,
110
- build: {
111
- rscOutputPath: handlerOptions.build.rscOutputPath,
112
- },
113
- });
114
- if (pageAndPropsResult.type === "success") {
115
- PageComponent = pageAndPropsResult.PageComponent;
116
- // Always use the props returned from the props function
117
- // Root components can handle empty props with their defaults
118
- pageProps = pageAndPropsResult.pageProps || {};
119
- if (handlerOptions.verbose) {
120
- handlerOptions.logger?.info(`[renderPage.server] Successfully loaded page and props for route ${handlerOptions.route}: pageProps=${JSON.stringify(pageProps)}`);
121
- }
122
- }
123
- else {
124
- handlerOptions.logger?.warn(`Failed to load page and props from ${handlerOptions.pagePath}: ${pageAndPropsResult.error?.message || "Unknown error"}`);
125
- }
126
- }
127
- catch (error) {
128
- handlerOptions.logger?.warn(`Error loading page and props from ${handlerOptions.pagePath}: ${error instanceof Error ? error.message : String(error)}`);
129
- }
130
- }
131
- // Load Root component
132
- if (handlerOptions.rootPath) {
133
- try {
134
- const rootResult = await resolveComponent({
135
- componentPath: handlerOptions.rootPath,
136
- exportName: handlerOptions.rootExportName,
137
- loader: handlerOptions.loader,
138
- });
139
- if (rootResult.type === "success") {
140
- RootComponent = rootResult.component;
141
- }
142
- else {
143
- handlerOptions.logger?.warn(`Failed to load Root component from ${handlerOptions.rootPath}: ${rootResult.error?.message || "Unknown error"}`);
144
- }
145
- }
146
- catch (error) {
147
- handlerOptions.logger?.warn(`Error loading Root component from ${handlerOptions.rootPath}: ${error instanceof Error ? error.message : String(error)}`);
148
- }
149
- }
150
- // Load Html component
151
- if (handlerOptions.htmlPath) {
152
- try {
153
- const htmlResult = await resolveComponent({
154
- componentPath: handlerOptions.htmlPath,
155
- exportName: handlerOptions.htmlExportName,
156
- loader: handlerOptions.loader,
157
- });
158
- if (htmlResult.type === "success") {
159
- HtmlComponent = htmlResult.component;
160
- }
161
- else {
162
- handlerOptions.logger?.warn(`Failed to load Html component from ${handlerOptions.htmlPath}: ${htmlResult.error?.message || "Unknown error"}`);
163
- }
164
- }
165
- catch (error) {
166
- handlerOptions.logger?.warn(`Error loading Html component from ${handlerOptions.htmlPath}: ${error instanceof Error ? error.message : String(error)}`);
167
- }
6
+ import { createRenderMetrics } from '../metrics/createRenderMetrics.js';
7
+ import { routeToURL } from '../utils/routeToURL.js';
8
+ import { handleError } from '../error/handleError.js';
9
+ import { assertReactServer } from '../config/getCondition.js';
10
+ import { renderRscStream } from '../stream/renderRscStream.server.js';
11
+ import { createMainThreadHandlers } from '../stream/createMainThreadHandlers.js';
12
+ import { createRscToHtmlStream } from './rscToHtmlStream.server.js';
13
+ import { resolveComponent } from '../helpers/resolveComponent.js';
14
+ import { resolvePageAndProps } from '../helpers/resolvePageAndProps.js';
15
+ import { Root } from '../components/root.js';
16
+ import { Html } from '../components/html.js';
17
+ import { createStreamMetrics } from '../metrics/createStreamMetrics.js';
18
+ import { join } from 'node:path';
19
+ import { trackHeadlessStreamError, createHeadlessStreamState, hasHeadlessStreamError } from '../helpers/headlessStreamState.js';
20
+
21
+ const renderPage = async function* renderPage2(handlerOptions) {
22
+ assertReactServer();
23
+ const baseDir = join(
24
+ handlerOptions.build.outDir,
25
+ handlerOptions.build.static
26
+ );
27
+ const routePath = handlerOptions.route.replace(/^\//, "");
28
+ const htmlMetrics = createRenderMetrics({
29
+ route: handlerOptions.route,
30
+ type: "html",
31
+ fromMainThread: false,
32
+ // Server: HTML rendered in worker
33
+ fromRscWorker: false,
34
+ fromHtmlWorker: true,
35
+ baseDir,
36
+ routePath,
37
+ fileName: handlerOptions.build.htmlOutputPath,
38
+ outputPath: join(baseDir, routePath, handlerOptions.build.htmlOutputPath)
39
+ });
40
+ const rscFullMetrics = createRenderMetrics({
41
+ route: handlerOptions.route,
42
+ type: "rsc-full",
43
+ fromMainThread: true,
44
+ // Server: RSC rendered on main thread
45
+ fromRscWorker: false,
46
+ fromHtmlWorker: false
47
+ });
48
+ const rscHeadlessMetrics = createRenderMetrics({
49
+ route: handlerOptions.route,
50
+ type: "rsc-headless",
51
+ fromMainThread: true,
52
+ // Server: RSC rendered on main thread
53
+ fromRscWorker: false,
54
+ fromHtmlWorker: false,
55
+ baseDir,
56
+ routePath,
57
+ fileName: handlerOptions.build.rscOutputPath,
58
+ outputPath: join(baseDir, routePath, handlerOptions.build.rscOutputPath)
59
+ });
60
+ let headlessRscHandler = null;
61
+ let fullRscHandler = null;
62
+ let htmlTransformStream = null;
63
+ let headlessStreamErrored = false;
64
+ let headlessError = null;
65
+ let htmlStreamErrored = false;
66
+ let htmlStreamError = null;
67
+ const headlessStreamState = createHeadlessStreamState();
68
+ try {
69
+ if (handlerOptions.verbose) {
70
+ handlerOptions.logger?.info(
71
+ `[renderPage.server] Server-side rendering for route: ${handlerOptions.route}`
72
+ );
73
+ }
74
+ if (!handlerOptions.url) {
75
+ handlerOptions.url = routeToURL(
76
+ handlerOptions.route,
77
+ handlerOptions.moduleBaseURL,
78
+ handlerOptions.build.rscOutputPath
79
+ );
80
+ }
81
+ let PageComponent = null;
82
+ let RootComponent = null;
83
+ let HtmlComponent = null;
84
+ let pageProps = {};
85
+ if (handlerOptions.pagePath) {
86
+ try {
87
+ const pageAndPropsResult = await resolvePageAndProps({
88
+ pagePath: handlerOptions.pagePath,
89
+ pageExportName: handlerOptions.pageExportName,
90
+ propsPath: handlerOptions.propsPath,
91
+ propsExportName: handlerOptions.propsExportName,
92
+ loader: handlerOptions.loader,
93
+ verbose: handlerOptions.verbose,
94
+ logger: handlerOptions.logger,
95
+ route: handlerOptions.route,
96
+ url: handlerOptions.url,
97
+ moduleBaseURL: handlerOptions.moduleBaseURL,
98
+ build: {
99
+ rscOutputPath: handlerOptions.build.rscOutputPath
100
+ }
101
+ });
102
+ if (pageAndPropsResult.type === "success") {
103
+ PageComponent = pageAndPropsResult.PageComponent;
104
+ pageProps = pageAndPropsResult.pageProps || {};
105
+ if (handlerOptions.verbose) {
106
+ handlerOptions.logger?.info(
107
+ `[renderPage.server] Successfully loaded page and props for route ${handlerOptions.route}: pageProps=${JSON.stringify(pageProps)}`
108
+ );
109
+ }
110
+ } else {
111
+ handlerOptions.logger?.warn(
112
+ `Failed to load page and props from ${handlerOptions.pagePath}: ${pageAndPropsResult.error?.message || "Unknown error"}`
113
+ );
168
114
  }
169
- // Use defaults if components are still not loaded
170
- if (!RootComponent) {
171
- RootComponent = DefaultRoot;
115
+ } catch (error) {
116
+ handlerOptions.logger?.warn(
117
+ `Error loading page and props from ${handlerOptions.pagePath}: ${error instanceof Error ? error.message : String(error)}`
118
+ );
119
+ }
120
+ }
121
+ if (handlerOptions.rootPath) {
122
+ try {
123
+ const rootResult = await resolveComponent({
124
+ componentPath: handlerOptions.rootPath,
125
+ exportName: handlerOptions.rootExportName,
126
+ loader: handlerOptions.loader
127
+ });
128
+ if (rootResult.type === "success") {
129
+ RootComponent = rootResult.component;
130
+ } else {
131
+ handlerOptions.logger?.warn(
132
+ `Failed to load Root component from ${handlerOptions.rootPath}: ${rootResult.error?.message || "Unknown error"}`
133
+ );
172
134
  }
173
- if (!HtmlComponent) {
174
- HtmlComponent = DefaultHtml;
135
+ } catch (error) {
136
+ handlerOptions.logger?.warn(
137
+ `Error loading Root component from ${handlerOptions.rootPath}: ${error instanceof Error ? error.message : String(error)}`
138
+ );
139
+ }
140
+ }
141
+ if (handlerOptions.htmlPath) {
142
+ try {
143
+ const htmlResult = await resolveComponent({
144
+ componentPath: handlerOptions.htmlPath,
145
+ exportName: handlerOptions.htmlExportName,
146
+ loader: handlerOptions.loader
147
+ });
148
+ if (htmlResult.type === "success") {
149
+ HtmlComponent = htmlResult.component;
150
+ } else {
151
+ handlerOptions.logger?.warn(
152
+ `Failed to load Html component from ${handlerOptions.htmlPath}: ${htmlResult.error?.message || "Unknown error"}`
153
+ );
175
154
  }
176
- // Ensure we have all required components
177
- if (!PageComponent || !RootComponent || !HtmlComponent) {
178
- yield {
179
- type: "error",
180
- error: new Error(`Component resolution failed: missing required components (Page: ${!!PageComponent}, Root: ${!!RootComponent}, Html: ${!!HtmlComponent})`),
181
- metrics: {
182
- rscFull: rscFullMetrics,
183
- rscHeadless: rscHeadlessMetrics,
184
- html: htmlMetrics,
185
- },
186
- };
187
- return;
155
+ } catch (error) {
156
+ handlerOptions.logger?.warn(
157
+ `Error loading Html component from ${handlerOptions.htmlPath}: ${error instanceof Error ? error.message : String(error)}`
158
+ );
159
+ }
160
+ }
161
+ if (!RootComponent) {
162
+ RootComponent = Root;
163
+ }
164
+ if (!HtmlComponent) {
165
+ HtmlComponent = Html;
166
+ }
167
+ if (!PageComponent || !RootComponent || !HtmlComponent) {
168
+ yield {
169
+ type: "error",
170
+ error: new Error(
171
+ `Component resolution failed: missing required components (Page: ${!!PageComponent}, Root: ${!!RootComponent}, Html: ${!!HtmlComponent})`
172
+ ),
173
+ metrics: {
174
+ rscFull: rscFullMetrics,
175
+ rscHeadless: rscHeadlessMetrics,
176
+ html: htmlMetrics
188
177
  }
189
- // Create handler options with resolved components and props
190
- const uniqueId = handlerOptions.id ?? `${handlerOptions.route}?id=${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
191
- const newHandlerOptions = {
192
- ...handlerOptions,
193
- id: uniqueId,
194
- url: `${handlerOptions.url}`,
195
- route: `${handlerOptions.route}`,
196
- PageComponent,
197
- RootComponent,
198
- HtmlComponent,
199
- pageProps,
200
- };
178
+ };
179
+ return;
180
+ }
181
+ const uniqueId = handlerOptions.id ?? `${handlerOptions.route}?id=${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
182
+ const newHandlerOptions = {
183
+ ...handlerOptions,
184
+ id: uniqueId,
185
+ url: `${handlerOptions.url}`,
186
+ route: `${handlerOptions.route}`,
187
+ PageComponent,
188
+ RootComponent,
189
+ HtmlComponent,
190
+ pageProps
191
+ };
192
+ if (handlerOptions.verbose) {
193
+ handlerOptions.logger?.info(
194
+ `[renderPage.server] Created newHandlerOptions for route ${handlerOptions.route} with pageProps: ${JSON.stringify(pageProps)}`
195
+ );
196
+ }
197
+ const headlessHandlers = createMainThreadHandlers(
198
+ handlerOptions,
199
+ (error, isPanic) => {
201
200
  if (handlerOptions.verbose) {
202
- handlerOptions.logger?.info(`[renderPage.server] Created newHandlerOptions for route ${handlerOptions.route} with pageProps: ${JSON.stringify(pageProps)}`);
201
+ handlerOptions.logger?.info(
202
+ `[renderPage.server] Headless stream error handler called for route ${handlerOptions.route}: ${error.message}, isPanic: ${isPanic}`
203
+ );
203
204
  }
204
- // Create headless RSC handler (for .rsc file) - with proper error handling
205
- const headlessHandlers = createMainThreadHandlers(handlerOptions, (error, isPanic) => {
206
- if (handlerOptions.verbose) {
207
- handlerOptions.logger?.info(`[renderPage.server] Headless stream error handler called for route ${handlerOptions.route}: ${error.message}, isPanic: ${isPanic}`);
208
- }
209
- // Track if the headless stream had errors
210
- headlessStreamErrored = true;
211
- headlessError = error instanceof Error ? error : new Error("Headless RSC stream failed");
212
- // Track headless stream errors for conditional reuse logic (like RSC worker)
213
- trackHeadlessStreamError(headlessStreamState, handlerOptions.route, headlessError);
214
- if (handlerOptions.verbose) {
215
- handlerOptions.logger?.info(`[renderPage.server] Stored headless stream error for route ${handlerOptions.route} in headlessStreamErrors map`);
216
- }
217
- // Store panic errors for later handling
218
- if (isPanic) {
219
- // For panic threshold "all_errors", the panic error will be handled by renderPages
220
- if (handlerOptions.verbose) {
221
- handlerOptions.logger?.info(`[renderPage.server] Panic error detected for route ${handlerOptions.route}, will be handled by renderPages`);
222
- }
223
- }
224
- });
225
- // Override onData to track metrics
226
- headlessHandlers.onData = (_id, chunk) => {
227
- rscHeadlessMetrics.chunks++;
228
- rscHeadlessMetrics.streamMetrics.bytes += chunk.length;
229
- };
230
- headlessRscHandler = renderRscStream({
231
- ...newHandlerOptions,
232
- htmlPath: '', // Headless RSC - no HTML wrapper
233
- // If we expect errors, provide a safe Page component that doesn't throw
234
- PageComponent: newHandlerOptions.PageComponent, // Use original for now, will be overridden if errors occur
235
- }, headlessHandlers);
236
- // Note: Panic errors will be yielded from the error handler when they occur
237
- // No need to check shouldYieldPanicError here as it's set asynchronously
238
- // Store PageComponent for reuse when headless stream completes (like RSC worker)
239
- headlessRscHandler.rscStream.on('end', () => {
240
- // Only store if this is a headless stream and no errors occurred (like RSC worker)
241
- if (!hasHeadlessStreamError(headlessStreamState, handlerOptions.route)) {
242
- headlessStreamState.elements.set(uniqueId, {
243
- PageComponent: newHandlerOptions.PageComponent,
244
- errored: false
245
- });
246
- if (handlerOptions.verbose) {
247
- handlerOptions.logger?.info(`[renderPage.server] Stored PageComponent for headless stream ${uniqueId}`);
248
- }
249
- }
250
- else {
251
- if (handlerOptions.verbose) {
252
- handlerOptions.logger?.info(`[renderPage.server] Headless stream errored for route ${handlerOptions.route}, not storing PageComponent for reuse`);
253
- }
254
- }
255
- });
256
- // Create full RSC handler (for HTML generation) - reuse headless stream elements if no errors
257
- // For server-side, we create both streams in parallel like the client-side
258
- let fullPanicError = null;
259
- const fullHandlers = createMainThreadHandlers(handlerOptions, (error, isPanic) => {
260
- // If this is a panic error, store it to be handled later
261
- if (isPanic) {
262
- fullPanicError = error instanceof Error ? error : new Error("Full RSC stream failed");
263
- }
264
- });
265
- // Override onData to track metrics
266
- fullHandlers.onData = (_id, chunk) => {
267
- rscFullMetrics.chunks++;
268
- rscFullMetrics.streamMetrics.bytes += chunk.length;
269
- };
270
- // Create full RSC handler options - use React.Fragment if headless stream had errors (like RSC worker)
271
- // Check if there are any existing headless stream errors for this route
272
- const hasExistingHeadlessError = hasHeadlessStreamError(headlessStreamState, handlerOptions.route);
273
- const shouldUseFallback = headlessStreamErrored || hasExistingHeadlessError;
205
+ headlessStreamErrored = true;
206
+ headlessError = error instanceof Error ? error : new Error("Headless RSC stream failed");
207
+ trackHeadlessStreamError(headlessStreamState, handlerOptions.route, headlessError);
274
208
  if (handlerOptions.verbose) {
275
- handlerOptions.logger?.info(`[renderPage.server] Creating full RSC handler options for route ${handlerOptions.route}: headlessStreamErrored=${headlessStreamErrored}, hasExistingHeadlessError=${hasExistingHeadlessError}, shouldUseFallback=${shouldUseFallback}`);
209
+ handlerOptions.logger?.info(
210
+ `[renderPage.server] Stored headless stream error for route ${handlerOptions.route} in headlessStreamErrors map`
211
+ );
212
+ }
213
+ if (isPanic) {
214
+ if (handlerOptions.verbose) {
215
+ handlerOptions.logger?.info(
216
+ `[renderPage.server] Panic error detected for route ${handlerOptions.route}, will be handled by renderPages`
217
+ );
218
+ }
276
219
  }
277
- // Create a wrapper PageComponent that returns null if there are headless stream errors
278
- const SafePageComponent = (props) => {
279
- // Check if there are any headless stream errors for this route
280
- const hasError = hasHeadlessStreamError(headlessStreamState, handlerOptions.route);
281
- if (hasError) {
282
- return null;
283
- }
284
- return newHandlerOptions.PageComponent(props);
285
- };
286
- const fullRscHandlerOptions = {
287
- ...newHandlerOptions,
288
- htmlPath: undefined, // Full RSC - include HTML wrapper
289
- headlessStreamElements: headlessStreamState.elements, // Pass the storage map for reuse
290
- // Use SafePageComponent that returns null when there are headless stream errors
291
- PageComponent: SafePageComponent,
292
- };
293
- // Create a PageComponent that uses React.use() to consume the headless stream and check for errors
294
- // Store the headless stream elements for reuse (like RSC worker does)
295
- // Listen for the headless stream to complete and store its elements
296
- headlessRscHandler.rscStream.on('end', () => {
297
- if (!hasHeadlessStreamError(headlessStreamState, handlerOptions.route)) {
298
- if (handlerOptions.verbose) {
299
- handlerOptions.logger?.info(`[renderPage.server] Headless stream completed successfully for route ${handlerOptions.route}`);
300
- }
301
- }
220
+ }
221
+ );
222
+ headlessHandlers.onData = (_id, chunk) => {
223
+ rscHeadlessMetrics.chunks++;
224
+ rscHeadlessMetrics.streamMetrics.bytes += chunk.length;
225
+ };
226
+ headlessRscHandler = renderRscStream(
227
+ {
228
+ ...newHandlerOptions,
229
+ htmlPath: "",
230
+ // Headless RSC - no HTML wrapper
231
+ // If we expect errors, provide a safe Page component that doesn't throw
232
+ PageComponent: newHandlerOptions.PageComponent
233
+ // Use original for now, will be overridden if errors occur
234
+ },
235
+ headlessHandlers
236
+ );
237
+ headlessRscHandler.rscStream.on("end", () => {
238
+ if (!hasHeadlessStreamError(headlessStreamState, handlerOptions.route)) {
239
+ headlessStreamState.elements.set(uniqueId, {
240
+ PageComponent: newHandlerOptions.PageComponent,
241
+ errored: false
302
242
  });
303
243
  if (handlerOptions.verbose) {
304
- handlerOptions.logger?.info(`[renderPage.server] Created PageComponent that uses React.use() to consume headless stream for route ${handlerOptions.route}`);
244
+ handlerOptions.logger?.info(`[renderPage.server] Stored PageComponent for headless stream ${uniqueId}`);
305
245
  }
306
- fullRscHandler = renderRscStream(fullRscHandlerOptions, fullHandlers);
307
- // Check for panic error after creating the handler
308
- if (fullPanicError) {
309
- yield {
310
- type: "error",
311
- error: fullPanicError,
312
- metrics: {
313
- rscFull: rscFullMetrics,
314
- rscHeadless: rscHeadlessMetrics,
315
- html: htmlMetrics,
316
- },
317
- };
318
- return;
246
+ } else {
247
+ if (handlerOptions.verbose) {
248
+ handlerOptions.logger?.info(`[renderPage.server] Headless stream errored for route ${handlerOptions.route}, not storing PageComponent for reuse`);
319
249
  }
320
- // Create HTML transform stream - need createRscToHtmlStream for async server actions
321
- htmlTransformStream = createRscToHtmlStream({
322
- id: handlerOptions.id,
323
- worker: handlerOptions.worker,
324
- route: handlerOptions.route,
325
- url: handlerOptions.url,
326
- moduleRootPath: handlerOptions.moduleRootPath,
327
- moduleBasePath: handlerOptions.moduleBasePath,
328
- moduleBaseURL: handlerOptions.moduleBaseURL,
329
- projectRoot: handlerOptions.projectRoot,
330
- build: handlerOptions.build,
331
- panicThreshold: handlerOptions.panicThreshold,
332
- verbose: handlerOptions.verbose,
333
- signal: handlerOptions.signal,
334
- logger: handlerOptions.logger,
335
- htmlWorker: handlerOptions.htmlWorker,
336
- clientPipeableStreamOptions: handlerOptions.clientPipeableStreamOptions,
337
- onMetrics: handlerOptions.onMetrics,
338
- htmlTimeout: handlerOptions.htmlTimeout || 15000,
339
- rscStream: fullRscHandler.rscStream,
340
- onError: (error, isPanic) => {
341
- // Track HTML stream errors
342
- htmlStreamErrored = true;
343
- htmlStreamError = error;
344
- if (isPanic) {
345
- // This is a panic error, it should be yielded as an error result
346
- if (handlerOptions.verbose) {
347
- handlerOptions.logger?.error(`[renderPage.server] HTML stream panic error for route ${handlerOptions.route}: ${error.message}`);
348
- }
349
- }
350
- else {
351
- // For non-panic errors, just log them
352
- if (handlerOptions.verbose) {
353
- handlerOptions.logger?.warn(`[renderPage.server] HTML stream error for route ${handlerOptions.route}: ${error.message}`);
354
- }
355
- }
356
- },
357
- });
358
- // Create stream wrappers for file writing - simplified like client side
359
- const rscStreamWrapper = {
360
- pipe: (destination) => {
361
- const streamMetrics = createStreamMetrics();
362
- streamMetrics.startTime = performance.now();
363
- // Use the headless RSC stream directly for the .rsc file
364
- const rscFileStream = headlessRscHandler.rscStream;
365
- rscFileStream.on("data", (chunk) => {
366
- streamMetrics.chunks++;
367
- streamMetrics.bytes += chunk.length;
368
- });
369
- rscFileStream.on("end", () => {
370
- streamMetrics.duration = performance.now() - streamMetrics.startTime;
371
- streamMetrics.endTime = performance.now();
372
- rscHeadlessMetrics.streamMetrics = streamMetrics;
373
- rscHeadlessMetrics.chunkRate = streamMetrics.chunks / (streamMetrics.duration / 1000);
374
- rscHeadlessMetrics.processingTime = streamMetrics.duration;
375
- rscHeadlessMetrics.memoryUsage = process.memoryUsage();
376
- rscHeadlessMetrics.chunks = streamMetrics.chunks;
377
- });
378
- rscFileStream.pipe(destination);
379
- return destination;
380
- },
381
- abort: () => headlessRscHandler.abort(),
382
- };
383
- const htmlStreamWrapper = {
384
- pipe: (destination) => {
385
- // Use the HTML transform stream's pipe method directly (same as client side)
386
- return htmlTransformStream.pipe(destination);
387
- },
388
- abort: () => {
389
- htmlTransformStream.abort();
390
- },
391
- on: (event, listener) => {
392
- // Forward error events from the HTML transform stream to the wrapper
393
- if (event === 'error') {
394
- // Access the actual stream from the transform result
395
- const htmlStream = htmlTransformStream.htmlStream;
396
- if (htmlStream && typeof htmlStream.on === 'function') {
397
- htmlStream.on('error', listener);
398
- }
399
- }
400
- return htmlStreamWrapper;
401
- },
402
- };
403
- // Wait for HTML stream to complete or error before yielding success
404
- // This ensures that any errors from the HTML stream are caught before we yield success
405
- await new Promise((resolve, reject) => {
406
- const timeout = setTimeout(() => {
407
- reject(new Error(`HTML stream timeout for route ${handlerOptions.route}`));
408
- }, handlerOptions.htmlTimeout || 15000);
409
- // Check if HTML stream already errored
410
- if (htmlStreamErrored) {
411
- clearTimeout(timeout);
412
- resolve(); // Let the panic threshold logic handle this at the renderPages level
413
- return;
414
- }
415
- // Set up a flag to track if we've resolved
416
- let resolved = false;
417
- // Create a wrapper that resolves the promise when the stream completes
418
- const originalPipe = htmlTransformStream.pipe;
419
- htmlTransformStream.pipe = function (destination) {
420
- const result = originalPipe.call(this, destination);
421
- // Listen for the destination stream to end
422
- destination.on('finish', () => {
423
- if (!resolved) {
424
- resolved = true;
425
- clearTimeout(timeout);
426
- resolve();
427
- }
428
- });
429
- destination.on('error', (error) => {
430
- if (!resolved) {
431
- resolved = true;
432
- clearTimeout(timeout);
433
- reject(error);
434
- }
435
- });
436
- return result;
437
- };
438
- // If we don't have a destination yet, resolve after a short delay
439
- // This handles the case where the stream is created but not yet piped
440
- setTimeout(() => {
441
- if (!resolved) {
442
- resolved = true;
443
- clearTimeout(timeout);
444
- resolve();
445
- }
446
- }, 100);
447
- });
448
- // Check for HTML stream errors after waiting for completion
449
- if (htmlStreamErrored) {
450
- yield {
451
- type: "error",
452
- error: htmlStreamError || new Error("HTML stream failed"),
453
- metrics: {
454
- rscFull: rscFullMetrics,
455
- rscHeadless: rscHeadlessMetrics,
456
- html: htmlMetrics,
457
- },
458
- };
459
- return;
250
+ }
251
+ });
252
+ let fullPanicError = null;
253
+ const fullHandlers = createMainThreadHandlers(
254
+ handlerOptions,
255
+ (error, isPanic) => {
256
+ if (isPanic) {
257
+ fullPanicError = error instanceof Error ? error : new Error("Full RSC stream failed");
460
258
  }
461
- // Yield success result - simplified like client side
462
- yield {
463
- type: "success",
464
- html: htmlStreamWrapper,
465
- rsc: rscStreamWrapper,
466
- metrics: {
467
- rscFull: rscFullMetrics,
468
- rscHeadless: rscHeadlessMetrics,
469
- html: htmlMetrics,
470
- },
471
- };
259
+ }
260
+ );
261
+ fullHandlers.onData = (_id, chunk) => {
262
+ rscFullMetrics.chunks++;
263
+ rscFullMetrics.streamMetrics.bytes += chunk.length;
264
+ };
265
+ const hasExistingHeadlessError = hasHeadlessStreamError(headlessStreamState, handlerOptions.route);
266
+ const shouldUseFallback = headlessStreamErrored || hasExistingHeadlessError;
267
+ if (handlerOptions.verbose) {
268
+ handlerOptions.logger?.info(
269
+ `[renderPage.server] Creating full RSC handler options for route ${handlerOptions.route}: headlessStreamErrored=${headlessStreamErrored}, hasExistingHeadlessError=${hasExistingHeadlessError}, shouldUseFallback=${shouldUseFallback}`
270
+ );
472
271
  }
473
- catch (err) {
272
+ const SafePageComponent = (props) => {
273
+ const hasError = hasHeadlessStreamError(headlessStreamState, handlerOptions.route);
274
+ if (hasError) {
275
+ return null;
276
+ }
277
+ return newHandlerOptions.PageComponent(props);
278
+ };
279
+ const fullRscHandlerOptions = {
280
+ ...newHandlerOptions,
281
+ htmlPath: void 0,
282
+ // Full RSC - include HTML wrapper
283
+ headlessStreamElements: headlessStreamState.elements,
284
+ // Pass the storage map for reuse
285
+ // Use SafePageComponent that returns null when there are headless stream errors
286
+ PageComponent: SafePageComponent
287
+ };
288
+ headlessRscHandler.rscStream.on("end", () => {
289
+ if (!hasHeadlessStreamError(headlessStreamState, handlerOptions.route)) {
474
290
  if (handlerOptions.verbose) {
475
- handlerOptions.logger?.error(`[renderPage.server] Error: ${JSON.stringify(err)}`);
291
+ handlerOptions.logger?.info(
292
+ `[renderPage.server] Headless stream completed successfully for route ${handlerOptions.route}`
293
+ );
476
294
  }
477
- // Clean up any resources
478
- try {
479
- if (headlessRscHandler)
480
- headlessRscHandler.abort();
481
- if (fullRscHandler)
482
- fullRscHandler.abort();
483
- if (htmlTransformStream)
484
- htmlTransformStream.abort();
295
+ }
296
+ });
297
+ if (handlerOptions.verbose) {
298
+ handlerOptions.logger?.info(
299
+ `[renderPage.server] Created PageComponent that uses React.use() to consume headless stream for route ${handlerOptions.route}`
300
+ );
301
+ }
302
+ fullRscHandler = renderRscStream(fullRscHandlerOptions, fullHandlers);
303
+ if (fullPanicError) {
304
+ yield {
305
+ type: "error",
306
+ error: fullPanicError,
307
+ metrics: {
308
+ rscFull: rscFullMetrics,
309
+ rscHeadless: rscHeadlessMetrics,
310
+ html: htmlMetrics
485
311
  }
486
- catch (cleanupError) {
487
- handlerOptions.logger?.warn(`Failed to cleanup streams on error: ${cleanupError}`);
312
+ };
313
+ return;
314
+ }
315
+ htmlTransformStream = createRscToHtmlStream({
316
+ id: handlerOptions.id,
317
+ worker: handlerOptions.worker,
318
+ route: handlerOptions.route,
319
+ url: handlerOptions.url,
320
+ moduleRootPath: handlerOptions.moduleRootPath,
321
+ moduleBasePath: handlerOptions.moduleBasePath,
322
+ moduleBaseURL: handlerOptions.moduleBaseURL,
323
+ projectRoot: handlerOptions.projectRoot,
324
+ build: handlerOptions.build,
325
+ panicThreshold: handlerOptions.panicThreshold,
326
+ verbose: handlerOptions.verbose,
327
+ signal: handlerOptions.signal,
328
+ logger: handlerOptions.logger,
329
+ htmlWorker: handlerOptions.htmlWorker,
330
+ clientPipeableStreamOptions: handlerOptions.clientPipeableStreamOptions,
331
+ onMetrics: handlerOptions.onMetrics,
332
+ htmlTimeout: handlerOptions.htmlTimeout || 15e3,
333
+ rscStream: fullRscHandler.rscStream,
334
+ onError: (error, isPanic) => {
335
+ htmlStreamErrored = true;
336
+ htmlStreamError = error;
337
+ if (isPanic) {
338
+ if (handlerOptions.verbose) {
339
+ handlerOptions.logger?.error(
340
+ `[renderPage.server] HTML stream panic error for route ${handlerOptions.route}: ${error.message}`
341
+ );
342
+ }
343
+ } else {
344
+ if (handlerOptions.verbose) {
345
+ handlerOptions.logger?.warn(
346
+ `[renderPage.server] HTML stream error for route ${handlerOptions.route}: ${error.message}`
347
+ );
348
+ }
349
+ }
350
+ }
351
+ });
352
+ const rscStreamWrapper = {
353
+ pipe: (destination) => {
354
+ const streamMetrics = createStreamMetrics();
355
+ streamMetrics.startTime = performance.now();
356
+ const rscFileStream = headlessRscHandler.rscStream;
357
+ rscFileStream.on("data", (chunk) => {
358
+ streamMetrics.chunks++;
359
+ streamMetrics.bytes += chunk.length;
360
+ });
361
+ rscFileStream.on("end", () => {
362
+ streamMetrics.duration = performance.now() - streamMetrics.startTime;
363
+ streamMetrics.endTime = performance.now();
364
+ rscHeadlessMetrics.streamMetrics = streamMetrics;
365
+ rscHeadlessMetrics.chunkRate = streamMetrics.chunks / (streamMetrics.duration / 1e3);
366
+ rscHeadlessMetrics.processingTime = streamMetrics.duration;
367
+ rscHeadlessMetrics.memoryUsage = process.memoryUsage();
368
+ rscHeadlessMetrics.chunks = streamMetrics.chunks;
369
+ });
370
+ rscFileStream.pipe(destination);
371
+ return destination;
372
+ },
373
+ abort: () => headlessRscHandler.abort()
374
+ };
375
+ const htmlStreamWrapper = {
376
+ pipe: (destination) => {
377
+ return htmlTransformStream.pipe(destination);
378
+ },
379
+ abort: () => {
380
+ htmlTransformStream.abort();
381
+ },
382
+ on: (event, listener) => {
383
+ if (event === "error") {
384
+ const htmlStream = htmlTransformStream.htmlStream;
385
+ if (htmlStream && typeof htmlStream.on === "function") {
386
+ htmlStream.on("error", listener);
387
+ }
488
388
  }
489
- const panicError = handleError({
490
- error: err,
491
- critical: false,
492
- logger: handlerOptions.logger,
493
- panicThreshold: handlerOptions.panicThreshold,
494
- context: `RenderPage Error (${handlerOptions.route})`,
389
+ return htmlStreamWrapper;
390
+ }
391
+ };
392
+ await new Promise((resolve, reject) => {
393
+ const timeout = setTimeout(() => {
394
+ reject(new Error(`HTML stream timeout for route ${handlerOptions.route}`));
395
+ }, handlerOptions.htmlTimeout || 15e3);
396
+ if (htmlStreamErrored) {
397
+ clearTimeout(timeout);
398
+ resolve();
399
+ return;
400
+ }
401
+ let resolved = false;
402
+ const originalPipe = htmlTransformStream.pipe;
403
+ htmlTransformStream.pipe = function(destination) {
404
+ const result = originalPipe.call(this, destination);
405
+ destination.on("finish", () => {
406
+ if (!resolved) {
407
+ resolved = true;
408
+ clearTimeout(timeout);
409
+ resolve();
410
+ }
411
+ });
412
+ destination.on("error", (error) => {
413
+ if (!resolved) {
414
+ resolved = true;
415
+ clearTimeout(timeout);
416
+ reject(error);
417
+ }
495
418
  });
496
- if (panicError != null) {
497
- yield {
498
- type: "error",
499
- error: panicError,
500
- metrics: {
501
- rscFull: rscFullMetrics,
502
- rscHeadless: rscHeadlessMetrics,
503
- html: htmlMetrics,
504
- },
505
- };
419
+ return result;
420
+ };
421
+ setTimeout(() => {
422
+ if (!resolved) {
423
+ resolved = true;
424
+ clearTimeout(timeout);
425
+ resolve();
426
+ }
427
+ }, 100);
428
+ });
429
+ if (htmlStreamErrored) {
430
+ yield {
431
+ type: "error",
432
+ error: htmlStreamError || new Error("HTML stream failed"),
433
+ metrics: {
434
+ rscFull: rscFullMetrics,
435
+ rscHeadless: rscHeadlessMetrics,
436
+ html: htmlMetrics
437
+ }
438
+ };
439
+ return;
440
+ }
441
+ yield {
442
+ type: "success",
443
+ html: htmlStreamWrapper,
444
+ rsc: rscStreamWrapper,
445
+ metrics: {
446
+ rscFull: rscFullMetrics,
447
+ rscHeadless: rscHeadlessMetrics,
448
+ html: htmlMetrics
449
+ }
450
+ };
451
+ } catch (err) {
452
+ if (handlerOptions.verbose) {
453
+ handlerOptions.logger?.error(`[renderPage.server] Error: ${JSON.stringify(err)}`);
454
+ }
455
+ try {
456
+ if (headlessRscHandler) headlessRscHandler.abort();
457
+ if (fullRscHandler) fullRscHandler.abort();
458
+ if (htmlTransformStream) htmlTransformStream.abort();
459
+ } catch (cleanupError) {
460
+ handlerOptions.logger?.warn(`Failed to cleanup streams on error: ${cleanupError}`);
461
+ }
462
+ const panicError = handleError({
463
+ error: err,
464
+ critical: false,
465
+ logger: handlerOptions.logger,
466
+ panicThreshold: handlerOptions.panicThreshold,
467
+ context: `RenderPage Error (${handlerOptions.route})`
468
+ });
469
+ if (panicError != null) {
470
+ yield {
471
+ type: "error",
472
+ error: panicError,
473
+ metrics: {
474
+ rscFull: rscFullMetrics,
475
+ rscHeadless: rscHeadlessMetrics,
476
+ html: htmlMetrics
506
477
  }
507
- else {
508
- yield {
509
- type: "skip",
510
- reason: err,
511
- html: {
512
- pipe: (destination) => {
513
- destination.end();
514
- return destination;
515
- },
516
- abort: () => { },
517
- },
518
- rsc: {
519
- pipe: (destination) => {
520
- destination.end();
521
- return destination;
522
- },
523
- abort: () => { },
524
- },
525
- metrics: {
526
- rscFull: rscFullMetrics,
527
- rscHeadless: rscHeadlessMetrics,
528
- html: htmlMetrics,
529
- },
530
- };
478
+ };
479
+ } else {
480
+ yield {
481
+ type: "skip",
482
+ reason: err,
483
+ html: {
484
+ pipe: (destination) => {
485
+ destination.end();
486
+ return destination;
487
+ },
488
+ abort: () => {
489
+ }
490
+ },
491
+ rsc: {
492
+ pipe: (destination) => {
493
+ destination.end();
494
+ return destination;
495
+ },
496
+ abort: () => {
497
+ }
498
+ },
499
+ metrics: {
500
+ rscFull: rscFullMetrics,
501
+ rscHeadless: rscHeadlessMetrics,
502
+ html: htmlMetrics
531
503
  }
504
+ };
532
505
  }
506
+ }
533
507
  };
508
+
509
+ export { renderPage };
510
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuZGVyUGFnZS5zZXJ2ZXIuanMiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3BsdWdpbi9yZWFjdC1zdGF0aWMvcmVuZGVyUGFnZS5zZXJ2ZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiByZW5kZXJQYWdlLnNlcnZlci50c1xuICpcbiAqIFBVUlBPU0U6IFNlcnZlci1zaWRlIHN0YXRpYyBwYWdlIHJlbmRlcmluZyBmb3IgUmVhY3QgU2VydmVyIENvbXBvbmVudHNcbiAqXG4gKiBBUkNISVRFQ1RVUkUgT1ZFUlZJRVc6XG4gKiBcbiAqIFNFUlZFUi1TSURFIHZzIENMSUVOVC1TSURFOlxuICogLSBTZXJ2ZXItc2lkZTogUlNDIGdlbmVyYXRpb24gaW4gbWFpbiB0aHJlYWQsIEhUTUwgZ2VuZXJhdGlvbiBpbiB3b3JrZXJcbiAqIC0gQ2xpZW50LXNpZGU6IFJTQyBnZW5lcmF0aW9uIGluIHdvcmtlciwgSFRNTCBnZW5lcmF0aW9uIGluIG1haW4gdGhyZWFkXG4gKiBcbiAqIEZMT1c6XG4gKiAxLiBDcmVhdGUgaGVhZGxlc3MgUlNDIHN0cmVhbSAoZm9yIC5yc2MgZmlsZSlcbiAqIDIuIENyZWF0ZSBmdWxsIFJTQyBzdHJlYW0gKGZvciBIVE1MIGdlbmVyYXRpb24pXG4gKiAzLiBDcmVhdGUgSFRNTCB0cmFuc2Zvcm0gc3RyZWFtIHRoYXQgY29udmVydHMgUlNDIHRvIEhUTUxcbiAqIDQuIEJvdGggc3RyZWFtcyBhcmUgcGlwZWQgdG8gZmlsZSB3cml0ZXJzXG4gKiBcbiAqIFNJTVBMSUZJRUQgQVBQUk9BQ0g6XG4gKiBUaGlzIGltcGxlbWVudGF0aW9uIGZvbGxvd3MgdGhlIHNhbWUgc2ltcGxlIHBhdHRlcm4gYXMgdGhlIGNsaWVudCBzaWRlLFxuICogYXZvaWRpbmcgY29tcGxleCBiYWNrcHJlc3N1cmUgaGFuZGxpbmcgYW5kIHJhY2UgY29uZGl0aW9ucy5cbiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVSZW5kZXJNZXRyaWNzIH0gZnJvbSBcIi4uL21ldHJpY3MvY3JlYXRlUmVuZGVyTWV0cmljcy5qc1wiO1xuaW1wb3J0IHsgcm91dGVUb1VSTCB9IGZyb20gXCIuLi91dGlscy9yb3V0ZVRvVVJMLmpzXCI7XG5pbXBvcnQgdHlwZSB7IFJlbmRlclBhZ2VGbiB9IGZyb20gXCIuL3R5cGVzLmpzXCI7XG5pbXBvcnQgeyBoYW5kbGVFcnJvciB9IGZyb20gXCIuLi9lcnJvci9oYW5kbGVFcnJvci5qc1wiO1xuaW1wb3J0IHsgYXNzZXJ0UmVhY3RTZXJ2ZXIgfSBmcm9tIFwiLi4vY29uZmlnL2dldENvbmRpdGlvbi5qc1wiO1xuXG5pbXBvcnQgeyByZW5kZXJSc2NTdHJlYW0gfSBmcm9tIFwiLi4vc3RyZWFtL3JlbmRlclJzY1N0cmVhbS5zZXJ2ZXIuanNcIjtcbmltcG9ydCB7IGNyZWF0ZU1haW5UaHJlYWRIYW5kbGVycyB9IGZyb20gXCIuLi9zdHJlYW0vY3JlYXRlTWFpblRocmVhZEhhbmRsZXJzLmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVSc2NUb0h0bWxTdHJlYW0gfSBmcm9tIFwiLi9yc2NUb0h0bWxTdHJlYW0uc2VydmVyLmpzXCI7XG5pbXBvcnQgeyByZXNvbHZlQ29tcG9uZW50IH0gZnJvbSBcIi4uL2hlbHBlcnMvcmVzb2x2ZUNvbXBvbmVudC5qc1wiO1xuaW1wb3J0IHsgcmVzb2x2ZVBhZ2VBbmRQcm9wcyB9IGZyb20gXCIuLi9oZWxwZXJzL3Jlc29sdmVQYWdlQW5kUHJvcHMuanNcIjtcbmltcG9ydCB7IFJvb3QgYXMgRGVmYXVsdFJvb3QgfSBmcm9tIFwiLi4vY29tcG9uZW50cy9yb290LmpzXCI7XG5pbXBvcnQgeyBIdG1sIGFzIERlZmF1bHRIdG1sIH0gZnJvbSBcIi4uL2NvbXBvbmVudHMvaHRtbC5qc1wiO1xuaW1wb3J0IHsgY3JlYXRlU3RyZWFtTWV0cmljcyB9IGZyb20gXCIuLi9tZXRyaWNzL2NyZWF0ZVN0cmVhbU1ldHJpY3MuanNcIjtcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBjcmVhdGVIZWFkbGVzc1N0cmVhbVN0YXRlLCB0cmFja0hlYWRsZXNzU3RyZWFtRXJyb3IsIGhhc0hlYWRsZXNzU3RyZWFtRXJyb3IgfSBmcm9tIFwiLi4vaGVscGVycy9oZWFkbGVzc1N0cmVhbVN0YXRlLmpzXCI7XG5cbmV4cG9ydCBjb25zdCByZW5kZXJQYWdlOiBSZW5kZXJQYWdlRm4gPSBhc3luYyBmdW5jdGlvbiogcmVuZGVyUGFnZShcbiAgaGFuZGxlck9wdGlvbnNcbikge1xuICAvLyBFbnN1cmUgd2UncmUgaW4gdGhlIGNvcnJlY3QgZW52aXJvbm1lbnRcbiAgYXNzZXJ0UmVhY3RTZXJ2ZXIoKTtcblxuICAvLyBDcmVhdGUgbWV0cmljcyB1cGZyb250IHdpdGggcHJvcGVyIHR5cGVzXG4gIGNvbnN0IGJhc2VEaXIgPSBqb2luKFxuICAgIGhhbmRsZXJPcHRpb25zLmJ1aWxkLm91dERpcixcbiAgICBoYW5kbGVyT3B0aW9ucy5idWlsZC5zdGF0aWNcbiAgKTtcbiAgY29uc3Qgcm91dGVQYXRoID0gaGFuZGxlck9wdGlvbnMucm91dGUucmVwbGFjZSgvXlxcLy8sIFwiXCIpO1xuXG4gIGNvbnN0IGh0bWxNZXRyaWNzID0gY3JlYXRlUmVuZGVyTWV0cmljcyh7XG4gICAgcm91dGU6IGhhbmRsZXJPcHRpb25zLnJvdXRlLFxuICAgIHR5cGU6IFwiaHRtbFwiLFxuICAgIGZyb21NYWluVGhyZWFkOiBmYWxzZSwgLy8gU2VydmVyOiBIVE1MIHJlbmRlcmVkIGluIHdvcmtlclxuICAgIGZyb21Sc2NXb3JrZXI6IGZhbHNlLFxuICAgIGZyb21IdG1sV29ya2VyOiB0cnVlLFxuICAgIGJhc2VEaXIsXG4gICAgcm91dGVQYXRoLFxuICAgIGZpbGVOYW1lOiBoYW5kbGVyT3B0aW9ucy5idWlsZC5odG1sT3V0cHV0UGF0aCxcbiAgICBvdXRwdXRQYXRoOiBqb2luKGJhc2VEaXIsIHJvdXRlUGF0aCwgaGFuZGxlck9wdGlvbnMuYnVpbGQuaHRtbE91dHB1dFBhdGgpLFxuICB9KTtcbiAgXG4gIGNvbnN0IHJzY0Z1bGxNZXRyaWNzID0gY3JlYXRlUmVuZGVyTWV0cmljcyh7XG4gICAgcm91dGU6IGhhbmRsZXJPcHRpb25zLnJvdXRlLFxuICAgIHR5cGU6IFwicnNjLWZ1bGxcIixcbiAgICBmcm9tTWFpblRocmVhZDogdHJ1ZSwgLy8gU2VydmVyOiBSU0MgcmVuZGVyZWQgb24gbWFpbiB0aHJlYWRcbiAgICBmcm9tUnNjV29ya2VyOiBmYWxzZSxcbiAgICBmcm9tSHRtbFdvcmtlcjogZmFsc2UsXG4gIH0pO1xuICBcbiAgY29uc3QgcnNjSGVhZGxlc3NNZXRyaWNzID0gY3JlYXRlUmVuZGVyTWV0cmljcyh7XG4gICAgcm91dGU6IGhhbmRsZXJPcHRpb25zLnJvdXRlLFxuICAgIHR5cGU6IFwicnNjLWhlYWRsZXNzXCIsXG4gICAgZnJvbU1haW5UaHJlYWQ6IHRydWUsIC8vIFNlcnZlcjogUlNDIHJlbmRlcmVkIG9uIG1haW4gdGhyZWFkXG4gICAgZnJvbVJzY1dvcmtlcjogZmFsc2UsXG4gICAgZnJvbUh0bWxXb3JrZXI6IGZhbHNlLFxuICAgIGJhc2VEaXIsXG4gICAgcm91dGVQYXRoLFxuICAgIGZpbGVOYW1lOiBoYW5kbGVyT3B0aW9ucy5idWlsZC5yc2NPdXRwdXRQYXRoLFxuICAgIG91dHB1dFBhdGg6IGpvaW4oYmFzZURpciwgcm91dGVQYXRoLCBoYW5kbGVyT3B0aW9ucy5idWlsZC5yc2NPdXRwdXRQYXRoKSxcbiAgfSk7XG5cbiAgLy8gRGVjbGFyZSB2YXJpYWJsZXMgb3V0c2lkZSB0cnkgYmxvY2tcbiAgbGV0IGhlYWRsZXNzUnNjSGFuZGxlcjogYW55ID0gbnVsbDtcbiAgbGV0IGZ1bGxSc2NIYW5kbGVyOiBhbnkgPSBudWxsO1xuICBsZXQgaHRtbFRyYW5zZm9ybVN0cmVhbTogYW55ID0gbnVsbDtcbiAgXG4gIC8vIEVycm9yIHRyYWNraW5nIHZhcmlhYmxlcyBmb3IgaGVhZGxlc3Mgc3RyZWFtXG4gIGxldCBoZWFkbGVzc1N0cmVhbUVycm9yZWQgPSBmYWxzZTtcbiAgbGV0IGhlYWRsZXNzRXJyb3I6IEVycm9yIHwgbnVsbCA9IG51bGw7XG4gIFxuICAvLyBFcnJvciB0cmFja2luZyB2YXJpYWJsZXMgZm9yIEhUTUwgc3RyZWFtXG4gIGxldCBodG1sU3RyZWFtRXJyb3JlZCA9IGZhbHNlO1xuICBsZXQgaHRtbFN0cmVhbUVycm9yOiBFcnJvciB8IG51bGwgPSBudWxsO1xuXG4gIC8vIFNlcnZlci1zaWRlIHN0cmVhbSByZXVzZSBzdG9yYWdlIChzaW1pbGFyIHRvIGNsaWVudC1zaWRlIGhlYWRsZXNzU3RyZWFtRWxlbWVudHMpXG4gIGNvbnN0IGhlYWRsZXNzU3RyZWFtU3RhdGUgPSBjcmVhdGVIZWFkbGVzc1N0cmVhbVN0YXRlKCk7XG5cbiAgdHJ5IHtcbiAgICBpZiAoaGFuZGxlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgaGFuZGxlck9wdGlvbnMubG9nZ2VyPy5pbmZvKFxuICAgICAgICBgW3JlbmRlclBhZ2Uuc2VydmVyXSBTZXJ2ZXItc2lkZSByZW5kZXJpbmcgZm9yIHJvdXRlOiAke2hhbmRsZXJPcHRpb25zLnJvdXRlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2V0IFVSTCBpZiBub3QgcHJvdmlkZWRcbiAgICBpZiAoIWhhbmRsZXJPcHRpb25zLnVybCkge1xuICAgICAgaGFuZGxlck9wdGlvbnMudXJsID0gcm91dGVUb1VSTChcbiAgICAgICAgaGFuZGxlck9wdGlvbnMucm91dGUsXG4gICAgICAgIGhhbmRsZXJPcHRpb25zLm1vZHVsZUJhc2VVUkwsXG4gICAgICAgIGhhbmRsZXJPcHRpb25zLmJ1aWxkLnJzY091dHB1dFBhdGhcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUmVzb2x2ZSBjb21wb25lbnRzIGFuZCBwcm9wcyB1c2luZyB0aGUgcHJvcGVyIGhlbHBlclxuICAgIGxldCBQYWdlQ29tcG9uZW50OiBhbnkgPSBudWxsO1xuICAgIGxldCBSb290Q29tcG9uZW50OiBhbnkgPSBudWxsO1xuICAgIGxldCBIdG1sQ29tcG9uZW50OiBhbnkgPSBudWxsO1xuICAgIGxldCBwYWdlUHJvcHM6IGFueSA9IHt9OyAvLyBJbml0aWFsaXplIGFzIGVtcHR5IG9iamVjdCAtIHByb3BzIGZ1bmN0aW9uIHdpbGwgcG9wdWxhdGUgaXRcblxuICAgIC8vIFVzZSByZXNvbHZlUGFnZUFuZFByb3BzIGhlbHBlciB0byBwcm9wZXJseSBsb2FkIHBhZ2UgYW5kIHByb3BzXG4gICAgaWYgKGhhbmRsZXJPcHRpb25zLnBhZ2VQYXRoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBwYWdlQW5kUHJvcHNSZXN1bHQgPSBhd2FpdCByZXNvbHZlUGFnZUFuZFByb3BzKHtcbiAgICAgICAgICBwYWdlUGF0aDogaGFuZGxlck9wdGlvbnMucGFnZVBhdGgsXG4gICAgICAgICAgcGFnZUV4cG9ydE5hbWU6IGhhbmRsZXJPcHRpb25zLnBhZ2VFeHBvcnROYW1lLFxuICAgICAgICAgIHByb3BzUGF0aDogaGFuZGxlck9wdGlvbnMucHJvcHNQYXRoLFxuICAgICAgICAgIHByb3BzRXhwb3J0TmFtZTogaGFuZGxlck9wdGlvbnMucHJvcHNFeHBvcnROYW1lLFxuICAgICAgICAgIGxvYWRlcjogaGFuZGxlck9wdGlvbnMubG9hZGVyLFxuICAgICAgICAgIHZlcmJvc2U6IGhhbmRsZXJPcHRpb25zLnZlcmJvc2UsXG4gICAgICAgICAgbG9nZ2VyOiBoYW5kbGVyT3B0aW9ucy5sb2dnZXIsXG4gICAgICAgICAgcm91dGU6IGhhbmRsZXJPcHRpb25zLnJvdXRlLFxuICAgICAgICAgIHVybDogaGFuZGxlck9wdGlvbnMudXJsLFxuICAgICAgICAgIG1vZHVsZUJhc2VVUkw6IGhhbmRsZXJPcHRpb25zLm1vZHVsZUJhc2VVUkwsXG4gICAgICAgICAgYnVpbGQ6IHtcbiAgICAgICAgICAgIHJzY091dHB1dFBhdGg6IGhhbmRsZXJPcHRpb25zLmJ1aWxkLnJzY091dHB1dFBhdGgsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHBhZ2VBbmRQcm9wc1Jlc3VsdC50eXBlID09PSBcInN1Y2Nlc3NcIikge1xuICAgICAgICAgIFBhZ2VDb21wb25lbnQgPSBwYWdlQW5kUHJvcHNSZXN1bHQuUGFnZUNvbXBvbmVudDtcbiAgICAgICAgICAvLyBBbHdheXMgdXNlIHRoZSBwcm9wcyByZXR1cm5lZCBmcm9tIHRoZSBwcm9wcyBmdW5jdGlvblxuICAgICAgICAgIC8vIFJvb3QgY29tcG9uZW50cyBjYW4gaGFuZGxlIGVtcHR5IHByb3BzIHdpdGggdGhlaXIgZGVmYXVsdHNcbiAgICAgICAgICBwYWdlUHJvcHMgPSBwYWdlQW5kUHJvcHNSZXN1bHQucGFnZVByb3BzIHx8IHt9O1xuICAgICAgICAgIFxuICAgICAgICAgIGlmIChoYW5kbGVyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/LmluZm8oXG4gICAgICAgICAgICAgIGBbcmVuZGVyUGFnZS5zZXJ2ZXJdIFN1Y2Nlc3NmdWxseSBsb2FkZWQgcGFnZSBhbmQgcHJvcHMgZm9yIHJvdXRlICR7aGFuZGxlck9wdGlvbnMucm91dGV9OiBwYWdlUHJvcHM9JHtKU09OLnN0cmluZ2lmeShwYWdlUHJvcHMpfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGhhbmRsZXJPcHRpb25zLmxvZ2dlcj8ud2FybihcbiAgICAgICAgICAgIGBGYWlsZWQgdG8gbG9hZCBwYWdlIGFuZCBwcm9wcyBmcm9tICR7aGFuZGxlck9wdGlvbnMucGFnZVBhdGh9OiAke1xuICAgICAgICAgICAgICBwYWdlQW5kUHJvcHNSZXN1bHQuZXJyb3I/Lm1lc3NhZ2UgfHwgXCJVbmtub3duIGVycm9yXCJcbiAgICAgICAgICAgIH1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaGFuZGxlck9wdGlvbnMubG9nZ2VyPy53YXJuKFxuICAgICAgICAgIGBFcnJvciBsb2FkaW5nIHBhZ2UgYW5kIHByb3BzIGZyb20gJHtoYW5kbGVyT3B0aW9ucy5wYWdlUGF0aH06ICR7XG4gICAgICAgICAgICBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcilcbiAgICAgICAgICB9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIExvYWQgUm9vdCBjb21wb25lbnRcbiAgICBpZiAoaGFuZGxlck9wdGlvbnMucm9vdFBhdGgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJvb3RSZXN1bHQgPSBhd2FpdCByZXNvbHZlQ29tcG9uZW50KHtcbiAgICAgICAgICBjb21wb25lbnRQYXRoOiBoYW5kbGVyT3B0aW9ucy5yb290UGF0aCxcbiAgICAgICAgICBleHBvcnROYW1lOiBoYW5kbGVyT3B0aW9ucy5yb290RXhwb3J0TmFtZSxcbiAgICAgICAgICBsb2FkZXI6IGhhbmRsZXJPcHRpb25zLmxvYWRlcixcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChyb290UmVzdWx0LnR5cGUgPT09IFwic3VjY2Vzc1wiKSB7XG4gICAgICAgICAgUm9vdENvbXBvbmVudCA9IHJvb3RSZXN1bHQuY29tcG9uZW50O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGhhbmRsZXJPcHRpb25zLmxvZ2dlcj8ud2FybihcbiAgICAgICAgICAgIGBGYWlsZWQgdG8gbG9hZCBSb290IGNvbXBvbmVudCBmcm9tICR7aGFuZGxlck9wdGlvbnMucm9vdFBhdGh9OiAke1xuICAgICAgICAgICAgICByb290UmVzdWx0LmVycm9yPy5tZXNzYWdlIHx8IFwiVW5rbm93biBlcnJvclwiXG4gICAgICAgICAgICB9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGhhbmRsZXJPcHRpb25zLmxvZ2dlcj8ud2FybihcbiAgICAgICAgICBgRXJyb3IgbG9hZGluZyBSb290IGNvbXBvbmVudCBmcm9tICR7aGFuZGxlck9wdGlvbnMucm9vdFBhdGh9OiAke1xuICAgICAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpXG4gICAgICAgICAgfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBMb2FkIEh0bWwgY29tcG9uZW50XG4gICAgaWYgKGhhbmRsZXJPcHRpb25zLmh0bWxQYXRoKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBodG1sUmVzdWx0ID0gYXdhaXQgcmVzb2x2ZUNvbXBvbmVudCh7XG4gICAgICAgICAgY29tcG9uZW50UGF0aDogaGFuZGxlck9wdGlvbnMuaHRtbFBhdGgsXG4gICAgICAgICAgZXhwb3J0TmFtZTogaGFuZGxlck9wdGlvbnMuaHRtbEV4cG9ydE5hbWUsXG4gICAgICAgICAgbG9hZGVyOiBoYW5kbGVyT3B0aW9ucy5sb2FkZXIsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoaHRtbFJlc3VsdC50eXBlID09PSBcInN1Y2Nlc3NcIikge1xuICAgICAgICAgIEh0bWxDb21wb25lbnQgPSBodG1sUmVzdWx0LmNvbXBvbmVudDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/Lndhcm4oXG4gICAgICAgICAgICBgRmFpbGVkIHRvIGxvYWQgSHRtbCBjb21wb25lbnQgZnJvbSAke2hhbmRsZXJPcHRpb25zLmh0bWxQYXRofTogJHtcbiAgICAgICAgICAgICAgaHRtbFJlc3VsdC5lcnJvcj8ubWVzc2FnZSB8fCBcIlVua25vd24gZXJyb3JcIlxuICAgICAgICAgICAgfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/Lndhcm4oXG4gICAgICAgICAgYEVycm9yIGxvYWRpbmcgSHRtbCBjb21wb25lbnQgZnJvbSAke2hhbmRsZXJPcHRpb25zLmh0bWxQYXRofTogJHtcbiAgICAgICAgICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKVxuICAgICAgICAgIH1gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVXNlIGRlZmF1bHRzIGlmIGNvbXBvbmVudHMgYXJlIHN0aWxsIG5vdCBsb2FkZWRcbiAgICBpZiAoIVJvb3RDb21wb25lbnQpIHtcbiAgICAgIFJvb3RDb21wb25lbnQgPSBEZWZhdWx0Um9vdCBhcyBhbnk7XG4gICAgfVxuICAgIGlmICghSHRtbENvbXBvbmVudCkge1xuICAgICAgSHRtbENvbXBvbmVudCA9IERlZmF1bHRIdG1sIGFzIGFueTtcbiAgICB9XG5cbiAgICAvLyBFbnN1cmUgd2UgaGF2ZSBhbGwgcmVxdWlyZWQgY29tcG9uZW50c1xuICAgIGlmICghUGFnZUNvbXBvbmVudCB8fCAhUm9vdENvbXBvbmVudCB8fCAhSHRtbENvbXBvbmVudCkge1xuICAgICAgeWllbGQge1xuICAgICAgICB0eXBlOiBcImVycm9yXCIsXG4gICAgICAgIGVycm9yOiBuZXcgRXJyb3IoXG4gICAgICAgICAgYENvbXBvbmVudCByZXNvbHV0aW9uIGZhaWxlZDogbWlzc2luZyByZXF1aXJlZCBjb21wb25lbnRzIChQYWdlOiAkeyEhUGFnZUNvbXBvbmVudH0sIFJvb3Q6ICR7ISFSb290Q29tcG9uZW50fSwgSHRtbDogJHshIUh0bWxDb21wb25lbnR9KWBcbiAgICAgICAgKSxcbiAgICAgICAgbWV0cmljczoge1xuICAgICAgICAgIHJzY0Z1bGw6IHJzY0Z1bGxNZXRyaWNzLFxuICAgICAgICAgIHJzY0hlYWRsZXNzOiByc2NIZWFkbGVzc01ldHJpY3MsXG4gICAgICAgICAgaHRtbDogaHRtbE1ldHJpY3MsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIENyZWF0ZSBoYW5kbGVyIG9wdGlvbnMgd2l0aCByZXNvbHZlZCBjb21wb25lbnRzIGFuZCBwcm9wc1xuICAgIGNvbnN0IHVuaXF1ZUlkID0gaGFuZGxlck9wdGlvbnMuaWQgPz8gYCR7aGFuZGxlck9wdGlvbnMucm91dGV9P2lkPSR7RGF0ZS5ub3coKX0tJHtNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHJpbmcoMiwgMTEpfWA7XG4gICAgY29uc3QgbmV3SGFuZGxlck9wdGlvbnMgPSB7XG4gICAgICAuLi5oYW5kbGVyT3B0aW9ucyxcbiAgICAgIGlkOiB1bmlxdWVJZCxcbiAgICAgIHVybDogYCR7aGFuZGxlck9wdGlvbnMudXJsfWAsXG4gICAgICByb3V0ZTogYCR7aGFuZGxlck9wdGlvbnMucm91dGV9YCxcbiAgICAgIFBhZ2VDb21wb25lbnQsXG4gICAgICBSb290Q29tcG9uZW50LFxuICAgICAgSHRtbENvbXBvbmVudCxcbiAgICAgIHBhZ2VQcm9wcyxcbiAgICB9O1xuICAgIFxuICAgIGlmIChoYW5kbGVyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/LmluZm8oXG4gICAgICAgIGBbcmVuZGVyUGFnZS5zZXJ2ZXJdIENyZWF0ZWQgbmV3SGFuZGxlck9wdGlvbnMgZm9yIHJvdXRlICR7aGFuZGxlck9wdGlvbnMucm91dGV9IHdpdGggcGFnZVByb3BzOiAke0pTT04uc3RyaW5naWZ5KHBhZ2VQcm9wcyl9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgaGVhZGxlc3MgUlNDIGhhbmRsZXIgKGZvciAucnNjIGZpbGUpIC0gd2l0aCBwcm9wZXIgZXJyb3IgaGFuZGxpbmdcbiAgICBjb25zdCBoZWFkbGVzc0hhbmRsZXJzID0gY3JlYXRlTWFpblRocmVhZEhhbmRsZXJzKFxuICAgICAgaGFuZGxlck9wdGlvbnMsXG4gICAgICAoZXJyb3IsIGlzUGFuaWMpID0+IHtcbiAgICAgICAgaWYgKGhhbmRsZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/LmluZm8oXG4gICAgICAgICAgICBgW3JlbmRlclBhZ2Uuc2VydmVyXSBIZWFkbGVzcyBzdHJlYW0gZXJyb3IgaGFuZGxlciBjYWxsZWQgZm9yIHJvdXRlICR7aGFuZGxlck9wdGlvbnMucm91dGV9OiAke2Vycm9yLm1lc3NhZ2V9LCBpc1BhbmljOiAke2lzUGFuaWN9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIFRyYWNrIGlmIHRoZSBoZWFkbGVzcyBzdHJlYW0gaGFkIGVycm9yc1xuICAgICAgICBoZWFkbGVzc1N0cmVhbUVycm9yZWQgPSB0cnVlO1xuICAgICAgICBoZWFkbGVzc0Vycm9yID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFwiSGVhZGxlc3MgUlNDIHN0cmVhbSBmYWlsZWRcIik7XG4gICAgICAgIFxuICAgICAgICAvLyBUcmFjayBoZWFkbGVzcyBzdHJlYW0gZXJyb3JzIGZvciBjb25kaXRpb25hbCByZXVzZSBsb2dpYyAobGlrZSBSU0Mgd29ya2VyKVxuICAgICAgICB0cmFja0hlYWRsZXNzU3RyZWFtRXJyb3IoaGVhZGxlc3NTdHJlYW1TdGF0ZSwgaGFuZGxlck9wdGlvbnMucm91dGUsIGhlYWRsZXNzRXJyb3IpO1xuICAgICAgICBcbiAgICAgICAgaWYgKGhhbmRsZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/LmluZm8oXG4gICAgICAgICAgICBgW3JlbmRlclBhZ2Uuc2VydmVyXSBTdG9yZWQgaGVhZGxlc3Mgc3RyZWFtIGVycm9yIGZvciByb3V0ZSAke2hhbmRsZXJPcHRpb25zLnJvdXRlfSBpbiBoZWFkbGVzc1N0cmVhbUVycm9ycyBtYXBgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gU3RvcmUgcGFuaWMgZXJyb3JzIGZvciBsYXRlciBoYW5kbGluZ1xuICAgICAgICBpZiAoaXNQYW5pYykge1xuICAgICAgICAgIC8vIEZvciBwYW5pYyB0aHJlc2hvbGQgXCJhbGxfZXJyb3JzXCIsIHRoZSBwYW5pYyBlcnJvciB3aWxsIGJlIGhhbmRsZWQgYnkgcmVuZGVyUGFnZXNcbiAgICAgICAgICBpZiAoaGFuZGxlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgaGFuZGxlck9wdGlvbnMubG9nZ2VyPy5pbmZvKFxuICAgICAgICAgICAgICBgW3JlbmRlclBhZ2Uuc2VydmVyXSBQYW5pYyBlcnJvciBkZXRlY3RlZCBmb3Igcm91dGUgJHtoYW5kbGVyT3B0aW9ucy5yb3V0ZX0sIHdpbGwgYmUgaGFuZGxlZCBieSByZW5kZXJQYWdlc2BcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgKTtcbiAgICBcbiAgICAvLyBPdmVycmlkZSBvbkRhdGEgdG8gdHJhY2sgbWV0cmljc1xuICAgIGhlYWRsZXNzSGFuZGxlcnMub25EYXRhID0gKF9pZCwgY2h1bmspID0+IHtcbiAgICAgIHJzY0hlYWRsZXNzTWV0cmljcy5jaHVua3MrKztcbiAgICAgIHJzY0hlYWRsZXNzTWV0cmljcy5zdHJlYW1NZXRyaWNzLmJ5dGVzICs9IGNodW5rLmxlbmd0aDtcbiAgICB9O1xuICAgIFxuICAgIGhlYWRsZXNzUnNjSGFuZGxlciA9IHJlbmRlclJzY1N0cmVhbShcbiAgICAgIHtcbiAgICAgICAgLi4ubmV3SGFuZGxlck9wdGlvbnMsXG4gICAgICAgIGh0bWxQYXRoOiAnJywgLy8gSGVhZGxlc3MgUlNDIC0gbm8gSFRNTCB3cmFwcGVyXG4gICAgICAgIC8vIElmIHdlIGV4cGVjdCBlcnJvcnMsIHByb3ZpZGUgYSBzYWZlIFBhZ2UgY29tcG9uZW50IHRoYXQgZG9lc24ndCB0aHJvd1xuICAgICAgICBQYWdlQ29tcG9uZW50OiBuZXdIYW5kbGVyT3B0aW9ucy5QYWdlQ29tcG9uZW50LCAvLyBVc2Ugb3JpZ2luYWwgZm9yIG5vdywgd2lsbCBiZSBvdmVycmlkZGVuIGlmIGVycm9ycyBvY2N1clxuICAgICAgfSxcbiAgICAgIGhlYWRsZXNzSGFuZGxlcnNcbiAgICApO1xuICAgIFxuICAgIC8vIE5vdGU6IFBhbmljIGVycm9ycyB3aWxsIGJlIHlpZWxkZWQgZnJvbSB0aGUgZXJyb3IgaGFuZGxlciB3aGVuIHRoZXkgb2NjdXJcbiAgICAvLyBObyBuZWVkIHRvIGNoZWNrIHNob3VsZFlpZWxkUGFuaWNFcnJvciBoZXJlIGFzIGl0J3Mgc2V0IGFzeW5jaHJvbm91c2x5XG5cbiAgICAvLyBTdG9yZSBQYWdlQ29tcG9uZW50IGZvciByZXVzZSB3aGVuIGhlYWRsZXNzIHN0cmVhbSBjb21wbGV0ZXMgKGxpa2UgUlNDIHdvcmtlcilcbiAgICBoZWFkbGVzc1JzY0hhbmRsZXIucnNjU3RyZWFtLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAvLyBPbmx5IHN0b3JlIGlmIHRoaXMgaXMgYSBoZWFkbGVzcyBzdHJlYW0gYW5kIG5vIGVycm9ycyBvY2N1cnJlZCAobGlrZSBSU0Mgd29ya2VyKVxuICAgICAgaWYgKCFoYXNIZWFkbGVzc1N0cmVhbUVycm9yKGhlYWRsZXNzU3RyZWFtU3RhdGUsIGhhbmRsZXJPcHRpb25zLnJvdXRlKSkge1xuICAgICAgICBoZWFkbGVzc1N0cmVhbVN0YXRlLmVsZW1lbnRzLnNldCh1bmlxdWVJZCwge1xuICAgICAgICAgIFBhZ2VDb21wb25lbnQ6IG5ld0hhbmRsZXJPcHRpb25zLlBhZ2VDb21wb25lbnQsXG4gICAgICAgICAgZXJyb3JlZDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChoYW5kbGVyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgaGFuZGxlck9wdGlvbnMubG9nZ2VyPy5pbmZvKGBbcmVuZGVyUGFnZS5zZXJ2ZXJdIFN0b3JlZCBQYWdlQ29tcG9uZW50IGZvciBoZWFkbGVzcyBzdHJlYW0gJHt1bmlxdWVJZH1gKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGhhbmRsZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/LmluZm8oYFtyZW5kZXJQYWdlLnNlcnZlcl0gSGVhZGxlc3Mgc3RyZWFtIGVycm9yZWQgZm9yIHJvdXRlICR7aGFuZGxlck9wdGlvbnMucm91dGV9LCBub3Qgc3RvcmluZyBQYWdlQ29tcG9uZW50IGZvciByZXVzZWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBDcmVhdGUgZnVsbCBSU0MgaGFuZGxlciAoZm9yIEhUTUwgZ2VuZXJhdGlvbikgLSByZXVzZSBoZWFkbGVzcyBzdHJlYW0gZWxlbWVudHMgaWYgbm8gZXJyb3JzXG4gICAgLy8gRm9yIHNlcnZlci1zaWRlLCB3ZSBjcmVhdGUgYm90aCBzdHJlYW1zIGluIHBhcmFsbGVsIGxpa2UgdGhlIGNsaWVudC1zaWRlXG4gICAgbGV0IGZ1bGxQYW5pY0Vycm9yOiBFcnJvciB8IG51bGwgPSBudWxsO1xuICAgIGNvbnN0IGZ1bGxIYW5kbGVycyA9IGNyZWF0ZU1haW5UaHJlYWRIYW5kbGVycyhcbiAgICAgIGhhbmRsZXJPcHRpb25zLFxuICAgICAgKGVycm9yLCBpc1BhbmljKSA9PiB7XG4gICAgICAgIC8vIElmIHRoaXMgaXMgYSBwYW5pYyBlcnJvciwgc3RvcmUgaXQgdG8gYmUgaGFuZGxlZCBsYXRlclxuICAgICAgICBpZiAoaXNQYW5pYykge1xuICAgICAgICAgIGZ1bGxQYW5pY0Vycm9yID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFwiRnVsbCBSU0Mgc3RyZWFtIGZhaWxlZFwiKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG4gICAgXG4gICAgLy8gT3ZlcnJpZGUgb25EYXRhIHRvIHRyYWNrIG1ldHJpY3NcbiAgICBmdWxsSGFuZGxlcnMub25EYXRhID0gKF9pZCwgY2h1bmspID0+IHtcbiAgICAgIHJzY0Z1bGxNZXRyaWNzLmNodW5rcysrO1xuICAgICAgcnNjRnVsbE1ldHJpY3Muc3RyZWFtTWV0cmljcy5ieXRlcyArPSBjaHVuay5sZW5ndGg7XG4gICAgfTtcbiAgICBcbiAgICAvLyBDcmVhdGUgZnVsbCBSU0MgaGFuZGxlciBvcHRpb25zIC0gdXNlIFJlYWN0LkZyYWdtZW50IGlmIGhlYWRsZXNzIHN0cmVhbSBoYWQgZXJyb3JzIChsaWtlIFJTQyB3b3JrZXIpXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBleGlzdGluZyBoZWFkbGVzcyBzdHJlYW0gZXJyb3JzIGZvciB0aGlzIHJvdXRlXG4gICAgY29uc3QgaGFzRXhpc3RpbmdIZWFkbGVzc0Vycm9yID0gaGFzSGVhZGxlc3NTdHJlYW1FcnJvcihoZWFkbGVzc1N0cmVhbVN0YXRlLCBoYW5kbGVyT3B0aW9ucy5yb3V0ZSk7XG4gICAgY29uc3Qgc2hvdWxkVXNlRmFsbGJhY2sgPSBoZWFkbGVzc1N0cmVhbUVycm9yZWQgfHwgaGFzRXhpc3RpbmdIZWFkbGVzc0Vycm9yO1xuICAgIFxuICAgIGlmIChoYW5kbGVyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICBoYW5kbGVyT3B0aW9ucy5sb2dnZXI/LmluZm8oXG4gICAgICAgIGBbcmVuZGVyUGFnZS5zZXJ2ZXJdIENyZWF0aW5nIGZ1bGwgUlNDIGhhbmRsZXIgb3B0aW9ucyBmb3Igcm91dGUgJHtoYW5kbGVyT3B0aW9ucy5yb3V0ZX06IGhlYWRsZXNzU3RyZWFtRXJyb3JlZD0ke2hlYWRsZXNzU3RyZWFtRXJyb3JlZH0sIGhhc0V4aXN0aW5nSGVhZGxlc3NFcnJvcj0ke2hhc0V4aXN0aW5nSGVhZGxlc3NFcnJvcn0sIHNob3VsZFVzZUZhbGxiYWNrPSR7c2hvdWxkVXNlRmFsbGJhY2t9YFxuICAgICAgKTtcbiAgICB9XG4gICAgXG4gICAgLy8gQ3JlYXRlIGEgd3JhcHBlciBQYWdlQ29tcG9uZW50IHRoYXQgcmV0dXJucyBudWxsIGlmIHRoZXJlIGFyZSBoZWFkbGVzcyBzdHJlYW0gZXJyb3JzXG4gICAgY29uc3QgU2FmZVBhZ2VDb21wb25lbnQgPSAocHJvcHM6IGFueSkgPT4ge1xuICAgICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBoZWFkbGVzcyBzdHJlYW0gZXJyb3JzIGZvciB0aGlzIHJvdXRlXG4gICAgICBjb25zdCBoYXNFcnJvciA9IGhhc0hlYWRsZXNzU3RyZWFtRXJyb3IoaGVhZGxlc3NTdHJlYW1TdGF0ZSwgaGFuZGxlck9wdGlvbnMucm91dGUpO1xuICAgICAgaWYgKGhhc0Vycm9yKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5ld0hhbmRsZXJPcHRpb25zLlBhZ2VDb21wb25lbnQocHJvcHMpO1xuICAgIH07XG4gICAgXG4gICAgY29uc3QgZnVsbFJzY0hhbmRsZXJPcHRpb25zID0ge1xuICAgICAgLi4ubmV3SGFuZGxlck9wdGlvbnMsXG4gICAgICBodG1sUGF0aDogdW5kZWZpbmVkLCAvLyBGdWxsIFJTQyAtIGluY2x1ZGUgSFRNTCB3cmFwcGVyXG4gICAgICBoZWFkbGVzc1N0cmVhbUVsZW1lbnRzOiBoZWFkbGVzc1N0cmVhbVN0YXRlLmVsZW1lbnRzLCAvLyBQYXNzIHRoZSBzdG9yYWdlIG1hcCBmb3IgcmV1c2VcbiAgICAgIC8vIFVzZSBTYWZlUGFnZUNvbXBvbmVudCB0aGF0IHJldHVybnMgbnVsbCB3aGVuIHRoZXJlIGFyZSBoZWFkbGVzcyBzdHJlYW0gZXJyb3JzXG4gICAgICBQYWdlQ29tcG9uZW50OiBTYWZlUGFnZUNvbXBvbmVudCxcbiAgICB9O1xuICAgIFxuICAgIFxuICAgIC8vIENyZWF0ZSBhIFBhZ2VDb21wb25lbnQgdGhhdCB1c2VzIFJlYWN0LnVzZSgpIHRvIGNvbnN1bWUgdGhlIGhlYWRsZXNzIHN0cmVhbSBhbmQgY2hlY2sgZm9yIGVycm9yc1xuXG4gICAgLy8gU3RvcmUgdGhlIGhlYWRsZXNzIHN0cmVhbSBlbGVtZW50cyBmb3IgcmV1c2UgKGxpa2UgUlNDIHdvcmtlciBkb2VzKVxuICAgIFxuICAgIC8vIExpc3RlbiBmb3IgdGhlIGhlYWRsZXNzIHN0cmVhbSB0byBjb21wbGV0ZSBhbmQgc3RvcmUgaXRzIGVsZW1lbnRzXG4gICAgaGVhZGxlc3NSc2NIYW5kbGVyLnJzY1N0cmVhbS5vbignZW5kJywgKCkgPT4ge1xuICAgICAgaWYgKCFoYXNIZWFkbGVzc1N0cmVhbUVycm9yKGhlYWRsZXNzU3RyZWFtU3RhdGUsIGhhbmRsZXJPcHRpb25zLnJvdXRlKSkge1xuICAgICAgICBpZiAoaGFuZGxlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgIGhhbmRsZXJPcHRpb25zLmxvZ2dlcj8uaW5mbyhcbiAgICAgICAgICAgIGBbcmVuZGVyUGFnZS5zZXJ2ZXJdIEhlYWRsZXNzIHN0cmVhbSBjb21wbGV0ZWQgc3VjY2Vzc2Z1bGx5IGZvciByb3V0ZSAke2hhbmRsZXJPcHRpb25zLnJvdXRlfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBcbiAgICBpZiAoaGFuZGxlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgaGFuZGxlck9wdGlvbnMubG9nZ2VyPy5pbmZvKFxuICAgICAgICBgW3JlbmRlclBhZ2Uuc2VydmVyXSBDcmVhdGVkIFBhZ2VDb21wb25lbnQgdGhhdCB1c2VzIFJlYWN0LnVzZSgpIHRvIGNvbnN1bWUgaGVhZGxlc3Mgc3RyZWFtIGZvciByb3V0ZSAke2hhbmRsZXJPcHRpb25zLnJvdXRlfWBcbiAgICAgICk7XG4gICAgfVxuICAgIFxuICAgIGZ1bGxSc2NIYW5kbGVyID0gcmVuZGVyUnNjU3RyZWFtKGZ1bGxSc2NIYW5kbGVyT3B0aW9ucywgZnVsbEhhbmRsZXJzKTtcbiAgICBcbiAgICAvLyBDaGVjayBmb3IgcGFuaWMgZXJyb3IgYWZ0ZXIgY3JlYXRpbmcgdGhlIGhhbmRsZXJcbiAgICBpZiAoZnVsbFBhbmljRXJyb3IpIHtcbiAgICAgIHlpZWxkIHtcbiAgICAgICAgdHlwZTogXCJlcnJvclwiLFxuICAgICAgICBlcnJvcjogZnVsbFBhbmljRXJyb3IsXG4gICAgICAgIG1ldHJpY3M6IHtcbiAgICAgICAgICByc2NGdWxsOiByc2NGdWxsTWV0cmljcyxcbiAgICAgICAgICByc2NIZWFkbGVzczogcnNjSGVhZGxlc3NNZXRyaWNzLFxuICAgICAgICAgIGh0bWw6IGh0bWxNZXRyaWNzLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgSFRNTCB0cmFuc2Zvcm0gc3RyZWFtIC0gbmVlZCBjcmVhdGVSc2NUb0h0bWxTdHJlYW0gZm9yIGFzeW5jIHNlcnZlciBhY3Rpb25zXG4gICAgaHRtbFRyYW5zZm9ybVN0cmVhbSA9IGNyZWF0ZVJzY1RvSHRtbFN0cmVhbSh7XG4gICAgICBpZDogaGFuZGxlck9wdGlvbnMuaWQsXG4gICAgICB3b3JrZXI6IGhhbmRsZXJPcHRpb25zLndvcmtlcixcbiAgICAgIHJvdXRlOiBoYW5kbGVyT3B0aW9ucy5yb3V0ZSxcbiAgICAgIHVybDogaGFuZGxlck9wdGlvbnMudXJsLFxuICAgICAgbW9kdWxlUm9vdFBhdGg6IGhhbmRsZXJPcHRpb25zLm1vZHVsZVJvb3RQYXRoLFxuICAgICAgbW9kdWxlQmFzZVBhdGg6IGhhbmRsZXJPcHRpb25zLm1vZHVsZUJhc2VQYXRoLFxuICAgICAgbW9kdWxlQmFzZVVSTDogaGFuZGxlck9wdGlvbnMubW9kdWxlQmFzZVVSTCxcbiAgICAgIHByb2plY3RSb290OiBoYW5kbGVyT3B0aW9ucy5wcm9qZWN0Um9vdCxcbiAgICAgIGJ1aWxkOiBoYW5kbGVyT3B0aW9ucy5idWlsZCxcbiAgICAgIHBhbmljVGhyZXNob2xkOiBoYW5kbGVyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgIHZlcmJvc2U6IGhhbmRsZXJPcHRpb25zLnZlcmJvc2UsXG4gICAgICBzaWduYWw6IGhhbmRsZXJPcHRpb25zLnNpZ25hbCxcbiAgICAgIGxvZ2dlcjogaGFuZGxlck9wdGlvbnMubG9nZ2VyLFxuICAgICAgaHRtbFdvcmtlcjogaGFuZGxlck9wdGlvbnMuaHRtbFdvcmtlcixcbiAgICAgIGNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9uczogaGFuZGxlck9wdGlvbnMuY2xpZW50UGlwZWFibGVTdHJlYW1PcHRpb25zLFxuICAgICAgb25NZXRyaWNzOiBoYW5kbGVyT3B0aW9ucy5vbk1ldHJpY3MsXG4gICAgICBodG1sVGltZW91dDogaGFuZGxlck9wdGlvbnMuaHRtbFRpbWVvdXQgfHwgMTUwMDAsXG4gICAgICByc2NTdHJlYW06IGZ1bGxSc2NIYW5kbGVyLnJzY1N0cmVhbSxcbiAgICAgIG9uRXJyb3I6IChlcnJvciwgaXNQYW5pYykgPT4ge1xuICAgICAgICAvLyBUcmFjayBIVE1MIHN0cmVhbSBlcnJvcnNcbiAgICAgICAgaHRtbFN0cmVhbUVycm9yZWQgPSB0cnVlO1xuICAgICAgICBodG1sU3RyZWFtRXJyb3IgPSBlcnJvcjtcbiAgICAgICAgXG4gICAgICAgIGlmIChpc1BhbmljKSB7XG4gICAgICAgICAgLy8gVGhpcyBpcyBhIHBhbmljIGVycm9yLCBpdCBzaG91bGQgYmUgeWllbGRlZCBhcyBhbiBlcnJvciByZXN1bHRcbiAgICAgICAgICBpZiAoaGFuZGxlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgaGFuZGxlck9wdGlvbnMubG9nZ2VyPy5lcnJvcihcbiAgICAgICAgICAgICAgYFtyZW5kZXJQYWdlLnNlcnZlcl0gSFRNTCBzdHJlYW0gcGFuaWMgZXJyb3IgZm9yIHJvdXRlICR7aGFuZGxlck9wdGlvbnMucm91dGV9OiAke2Vycm9yLm1lc3NhZ2V9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRm9yIG5vbi1wYW5pYyBlcnJvcnMsIGp1c3QgbG9nIHRoZW1cbiAgICAgICAgICBpZiAoaGFuZGxlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgaGFuZGxlck9wdGlvbnMubG9nZ2VyPy53YXJuKFxuICAgICAgICAgICAgICBgW3JlbmRlclBhZ2Uuc2VydmVyXSBIVE1MIHN0cmVhbSBlcnJvciBmb3Igcm91dGUgJHtoYW5kbGVyT3B0aW9ucy5yb3V0ZX06ICR7ZXJyb3IubWVzc2FnZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIC8vIENyZWF0ZSBzdHJlYW0gd3JhcHBlcnMgZm9yIGZpbGUgd3JpdGluZyAtIHNpbXBsaWZpZWQgbGlrZSBjbGllbnQgc2lkZVxuICAgIGNvbnN0IHJzY1N0cmVhbVdyYXBwZXIgPSB7XG4gICAgICBwaXBlOiA8V3JpdGFibGUgZXh0ZW5kcyBOb2RlSlMuV3JpdGFibGVTdHJlYW0+KGRlc3RpbmF0aW9uOiBXcml0YWJsZSkgPT4ge1xuICAgICAgICBjb25zdCBzdHJlYW1NZXRyaWNzID0gY3JlYXRlU3RyZWFtTWV0cmljcygpO1xuICAgICAgICBzdHJlYW1NZXRyaWNzLnN0YXJ0VGltZSA9IHBlcmZvcm1hbmNlLm5vdygpO1xuXG4gICAgICAgIC8vIFVzZSB0aGUgaGVhZGxlc3MgUlNDIHN0cmVhbSBkaXJlY3RseSBmb3IgdGhlIC5yc2MgZmlsZVxuICAgICAgICBjb25zdCByc2NGaWxlU3RyZWFtID0gaGVhZGxlc3NSc2NIYW5kbGVyLnJzY1N0cmVhbTtcblxuICAgICAgICByc2NGaWxlU3RyZWFtLm9uKFwiZGF0YVwiLCAoY2h1bms6IEJ1ZmZlcikgPT4ge1xuICAgICAgICAgIHN0cmVhbU1ldHJpY3MuY2h1bmtzKys7XG4gICAgICAgICAgc3RyZWFtTWV0cmljcy5ieXRlcyArPSBjaHVuay5sZW5ndGg7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJzY0ZpbGVTdHJlYW0ub24oXCJlbmRcIiwgKCkgPT4ge1xuICAgICAgICAgIHN0cmVhbU1ldHJpY3MuZHVyYXRpb24gPSBwZXJmb3JtYW5jZS5ub3coKSAtIHN0cmVhbU1ldHJpY3Muc3RhcnRUaW1lO1xuICAgICAgICAgIHN0cmVhbU1ldHJpY3MuZW5kVGltZSA9IHBlcmZvcm1hbmNlLm5vdygpO1xuXG4gICAgICAgICAgcnNjSGVhZGxlc3NNZXRyaWNzLnN0cmVhbU1ldHJpY3MgPSBzdHJlYW1NZXRyaWNzO1xuICAgICAgICAgIHJzY0hlYWRsZXNzTWV0cmljcy5jaHVua1JhdGUgPSBzdHJlYW1NZXRyaWNzLmNodW5rcyAvIChzdHJlYW1NZXRyaWNzLmR1cmF0aW9uIC8gMTAwMCk7XG4gICAgICAgICAgcnNjSGVhZGxlc3NNZXRyaWNzLnByb2Nlc3NpbmdUaW1lID0gc3RyZWFtTWV0cmljcy5kdXJhdGlvbjtcbiAgICAgICAgICByc2NIZWFkbGVzc01ldHJpY3MubWVtb3J5VXNhZ2UgPSBwcm9jZXNzLm1lbW9yeVVzYWdlKCk7XG4gICAgICAgICAgcnNjSGVhZGxlc3NNZXRyaWNzLmNodW5rcyA9IHN0cmVhbU1ldHJpY3MuY2h1bmtzO1xuICAgICAgICB9KTtcblxuICAgICAgICByc2NGaWxlU3RyZWFtLnBpcGUoZGVzdGluYXRpb24pO1xuICAgICAgICByZXR1cm4gZGVzdGluYXRpb247XG4gICAgICB9LFxuICAgICAgYWJvcnQ6ICgpID0+IGhlYWRsZXNzUnNjSGFuZGxlci5hYm9ydCgpLFxuICAgIH07XG5cbiAgICBjb25zdCBodG1sU3RyZWFtV3JhcHBlciA9IHtcbiAgICAgIHBpcGU6IDxXcml0YWJsZSBleHRlbmRzIE5vZGVKUy5Xcml0YWJsZVN0cmVhbT4oZGVzdGluYXRpb246IFdyaXRhYmxlKSA9PiB7XG4gICAgICAgIC8vIFVzZSB0aGUgSFRNTCB0cmFuc2Zvcm0gc3RyZWFtJ3MgcGlwZSBtZXRob2QgZGlyZWN0bHkgKHNhbWUgYXMgY2xpZW50IHNpZGUpXG4gICAgICAgIHJldHVybiBodG1sVHJhbnNmb3JtU3RyZWFtLnBpcGUoZGVzdGluYXRpb24pO1xuICAgICAgfSxcbiAgICAgIGFib3J0OiAoKSA9PiB7XG4gICAgICAgIGh0bWxUcmFuc2Zvcm1TdHJlYW0uYWJvcnQoKTtcbiAgICAgIH0sXG4gICAgICBvbjogKGV2ZW50OiBzdHJpbmcsIGxpc3RlbmVyOiAoLi4uYXJnczogYW55W10pID0+IHZvaWQpID0+IHtcbiAgICAgICAgLy8gRm9yd2FyZCBlcnJvciBldmVudHMgZnJvbSB0aGUgSFRNTCB0cmFuc2Zvcm0gc3RyZWFtIHRvIHRoZSB3cmFwcGVyXG4gICAgICAgIGlmIChldmVudCA9PT0gJ2Vycm9yJykge1xuICAgICAgICAgIC8vIEFjY2VzcyB0aGUgYWN0dWFsIHN0cmVhbSBmcm9tIHRoZSB0cmFuc2Zvcm0gcmVzdWx0XG4gICAgICAgICAgY29uc3QgaHRtbFN0cmVhbSA9IChodG1sVHJhbnNmb3JtU3RyZWFtIGFzIGFueSkuaHRtbFN0cmVhbTtcbiAgICAgICAgICBpZiAoaHRtbFN0cmVhbSAmJiB0eXBlb2YgaHRtbFN0cmVhbS5vbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgaHRtbFN0cmVhbS5vbignZXJyb3InLCBsaXN0ZW5lcik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBodG1sU3RyZWFtV3JhcHBlcjtcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIC8vIFdhaXQgZm9yIEhUTUwgc3RyZWFtIHRvIGNvbXBsZXRlIG9yIGVycm9yIGJlZm9yZSB5aWVsZGluZyBzdWNjZXNzXG4gICAgLy8gVGhpcyBlbnN1cmVzIHRoYXQgYW55IGVycm9ycyBmcm9tIHRoZSBIVE1MIHN0cmVhbSBhcmUgY2F1Z2h0IGJlZm9yZSB3ZSB5aWVsZCBzdWNjZXNzXG4gICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICByZWplY3QobmV3IEVycm9yKGBIVE1MIHN0cmVhbSB0aW1lb3V0IGZvciByb3V0ZSAke2hhbmRsZXJPcHRpb25zLnJvdXRlfWApKTtcbiAgICAgIH0sIGhhbmRsZXJPcHRpb25zLmh0bWxUaW1lb3V0IHx8IDE1MDAwKTtcblxuICAgICAgLy8gQ2hlY2sgaWYgSFRNTCBzdHJlYW0gYWxyZWFkeSBlcnJvcmVkXG4gICAgICBpZiAoaHRtbFN0cmVhbUVycm9yZWQpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICByZXNvbHZlKCk7IC8vIExldCB0aGUgcGFuaWMgdGhyZXNob2xkIGxvZ2ljIGhhbmRsZSB0aGlzIGF0IHRoZSByZW5kZXJQYWdlcyBsZXZlbFxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIFNldCB1cCBhIGZsYWcgdG8gdHJhY2sgaWYgd2UndmUgcmVzb2x2ZWRcbiAgICAgIGxldCByZXNvbHZlZCA9IGZhbHNlO1xuICAgICAgXG4gICAgICAvLyBDcmVhdGUgYSB3cmFwcGVyIHRoYXQgcmVzb2x2ZXMgdGhlIHByb21pc2Ugd2hlbiB0aGUgc3RyZWFtIGNvbXBsZXRlc1xuICAgICAgY29uc3Qgb3JpZ2luYWxQaXBlID0gaHRtbFRyYW5zZm9ybVN0cmVhbS5waXBlO1xuICAgICAgaHRtbFRyYW5zZm9ybVN0cmVhbS5waXBlID0gZnVuY3Rpb24oZGVzdGluYXRpb246IGFueSkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBvcmlnaW5hbFBpcGUuY2FsbCh0aGlzLCBkZXN0aW5hdGlvbik7XG4gICAgICAgIFxuICAgICAgICAvLyBMaXN0ZW4gZm9yIHRoZSBkZXN0aW5hdGlvbiBzdHJlYW0gdG8gZW5kXG4gICAgICAgIGRlc3RpbmF0aW9uLm9uKCdmaW5pc2gnLCAoKSA9PiB7XG4gICAgICAgICAgaWYgKCFyZXNvbHZlZCkge1xuICAgICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICBkZXN0aW5hdGlvbi5vbignZXJyb3InLCAoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICAgICAgaWYgKCFyZXNvbHZlZCkge1xuICAgICAgICAgICAgcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH07XG4gICAgICBcbiAgICAgIC8vIElmIHdlIGRvbid0IGhhdmUgYSBkZXN0aW5hdGlvbiB5ZXQsIHJlc29sdmUgYWZ0ZXIgYSBzaG9ydCBkZWxheVxuICAgICAgLy8gVGhpcyBoYW5kbGVzIHRoZSBjYXNlIHdoZXJlIHRoZSBzdHJlYW0gaXMgY3JlYXRlZCBidXQgbm90IHlldCBwaXBlZFxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGlmICghcmVzb2x2ZWQpIHtcbiAgICAgICAgICByZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgfSwgMTAwKTtcbiAgICB9KTtcblxuICAgIC8vIENoZWNrIGZvciBIVE1MIHN0cmVhbSBlcnJvcnMgYWZ0ZXIgd2FpdGluZyBmb3IgY29tcGxldGlvblxuICAgIGlmIChodG1sU3RyZWFtRXJyb3JlZCkge1xuICAgICAgeWllbGQge1xuICAgICAgICB0eXBlOiBcImVycm9yXCIsXG4gICAgICAgIGVycm9yOiBodG1sU3RyZWFtRXJyb3IgfHwgbmV3IEVycm9yKFwiSFRNTCBzdHJlYW0gZmFpbGVkXCIpLFxuICAgICAgICBtZXRyaWNzOiB7XG4gICAgICAgICAgcnNjRnVsbDogcnNjRnVsbE1ldHJpY3MsXG4gICAgICAgICAgcnNjSGVhZGxlc3M6IHJzY0hlYWRsZXNzTWV0cmljcyxcbiAgICAgICAgICBodG1sOiBodG1sTWV0cmljcyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gWWllbGQgc3VjY2VzcyByZXN1bHQgLSBzaW1wbGlmaWVkIGxpa2UgY2xpZW50IHNpZGVcbiAgICB5aWVsZCB7XG4gICAgICB0eXBlOiBcInN1Y2Nlc3NcIixcbiAgICAgIGh0bWw6IGh0bWxTdHJlYW1XcmFwcGVyLFxuICAgICAgcnNjOiByc2NTdHJlYW1XcmFwcGVyLFxuICAgICAgbWV0cmljczoge1xuICAgICAgICByc2NGdWxsOiByc2NGdWxsTWV0cmljcyxcbiAgICAgICAgcnNjSGVhZGxlc3M6IHJzY0hlYWRsZXNzTWV0cmljcyxcbiAgICAgICAgaHRtbDogaHRtbE1ldHJpY3MsXG4gICAgICB9LFxuICAgIH0gYXMgY29uc3Q7XG5cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgaWYgKGhhbmRsZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgIGhhbmRsZXJPcHRpb25zLmxvZ2dlcj8uZXJyb3IoYFtyZW5kZXJQYWdlLnNlcnZlcl0gRXJyb3I6ICR7SlNPTi5zdHJpbmdpZnkoZXJyKX1gKTtcbiAgICB9XG5cbiAgICAvLyBDbGVhbiB1cCBhbnkgcmVzb3VyY2VzXG4gICAgdHJ5IHtcbiAgICAgIGlmIChoZWFkbGVzc1JzY0hhbmRsZXIpIGhlYWRsZXNzUnNjSGFuZGxlci5hYm9ydCgpO1xuICAgICAgaWYgKGZ1bGxSc2NIYW5kbGVyKSBmdWxsUnNjSGFuZGxlci5hYm9ydCgpO1xuICAgICAgaWYgKGh0bWxUcmFuc2Zvcm1TdHJlYW0pIGh0bWxUcmFuc2Zvcm1TdHJlYW0uYWJvcnQoKTtcbiAgICB9IGNhdGNoIChjbGVhbnVwRXJyb3I6IHVua25vd24pIHtcbiAgICAgIGhhbmRsZXJPcHRpb25zLmxvZ2dlcj8ud2FybihgRmFpbGVkIHRvIGNsZWFudXAgc3RyZWFtcyBvbiBlcnJvcjogJHtjbGVhbnVwRXJyb3J9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgIGVycm9yOiBlcnIsXG4gICAgICBjcml0aWNhbDogZmFsc2UsXG4gICAgICBsb2dnZXI6IGhhbmRsZXJPcHRpb25zLmxvZ2dlcixcbiAgICAgIHBhbmljVGhyZXNob2xkOiBoYW5kbGVyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgIGNvbnRleHQ6IGBSZW5kZXJQYWdlIEVycm9yICgke2hhbmRsZXJPcHRpb25zLnJvdXRlfSlgLFxuICAgIH0pO1xuXG4gICAgaWYgKHBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgeWllbGQge1xuICAgICAgICB0eXBlOiBcImVycm9yXCIsXG4gICAgICAgIGVycm9yOiBwYW5pY0Vycm9yLFxuICAgICAgICBtZXRyaWNzOiB7XG4gICAgICAgICAgcnNjRnVsbDogcnNjRnVsbE1ldHJpY3MsXG4gICAgICAgICAgcnNjSGVhZGxlc3M6IHJzY0hlYWRsZXNzTWV0cmljcyxcbiAgICAgICAgICBodG1sOiBodG1sTWV0cmljcyxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHlpZWxkIHtcbiAgICAgICAgdHlwZTogXCJza2lwXCIsXG4gICAgICAgIHJlYXNvbjogZXJyLFxuICAgICAgICBodG1sOiB7XG4gICAgICAgICAgcGlwZTogPFdyaXRhYmxlIGV4dGVuZHMgTm9kZUpTLldyaXRhYmxlU3RyZWFtPihkZXN0aW5hdGlvbjogV3JpdGFibGUpID0+IHtcbiAgICAgICAgICAgIGRlc3RpbmF0aW9uLmVuZCgpO1xuICAgICAgICAgICAgcmV0dXJuIGRlc3RpbmF0aW9uO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgYWJvcnQ6ICgpID0+IHt9LFxuICAgICAgICB9LFxuICAgICAgICByc2M6IHtcbiAgICAgICAgICBwaXBlOiA8V3JpdGFibGUgZXh0ZW5kcyBOb2RlSlMuV3JpdGFibGVTdHJlYW0+KGRlc3RpbmF0aW9uOiBXcml0YWJsZSkgPT4ge1xuICAgICAgICAgICAgZGVzdGluYXRpb24uZW5kKCk7XG4gICAgICAgICAgICByZXR1cm4gZGVzdGluYXRpb247XG4gICAgICAgICAgfSxcbiAgICAgICAgICBhYm9ydDogKCkgPT4ge30sXG4gICAgICAgIH0sXG4gICAgICAgIG1ldHJpY3M6IHtcbiAgICAgICAgICByc2NGdWxsOiByc2NGdWxsTWV0cmljcyxcbiAgICAgICAgICByc2NIZWFkbGVzczogcnNjSGVhZGxlc3NNZXRyaWNzLFxuICAgICAgICAgIGh0bWw6IGh0bWxNZXRyaWNzLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9XG4gIH1cbn07Il0sIm5hbWVzIjpbInJlbmRlclBhZ2UiLCJEZWZhdWx0Um9vdCIsIkRlZmF1bHRIdG1sIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXVDYSxNQUFBLFVBQUEsR0FBMkIsZ0JBQWdCQSxXQUFBQSxDQUN0RCxjQUNBLEVBQUE7QUFFQSxFQUFrQixpQkFBQSxFQUFBO0FBR2xCLEVBQUEsTUFBTSxPQUFVLEdBQUEsSUFBQTtBQUFBLElBQ2QsZUFBZSxLQUFNLENBQUEsTUFBQTtBQUFBLElBQ3JCLGVBQWUsS0FBTSxDQUFBO0FBQUEsR0FDdkI7QUFDQSxFQUFBLE1BQU0sU0FBWSxHQUFBLGNBQUEsQ0FBZSxLQUFNLENBQUEsT0FBQSxDQUFRLE9BQU8sRUFBRSxDQUFBO0FBRXhELEVBQUEsTUFBTSxjQUFjLG1CQUFvQixDQUFBO0FBQUEsSUFDdEMsT0FBTyxjQUFlLENBQUEsS0FBQTtBQUFBLElBQ3RCLElBQU0sRUFBQSxNQUFBO0FBQUEsSUFDTixjQUFnQixFQUFBLEtBQUE7QUFBQTtBQUFBLElBQ2hCLGFBQWUsRUFBQSxLQUFBO0FBQUEsSUFDZixjQUFnQixFQUFBLElBQUE7QUFBQSxJQUNoQixPQUFBO0FBQUEsSUFDQSxTQUFBO0FBQUEsSUFDQSxRQUFBLEVBQVUsZUFBZSxLQUFNLENBQUEsY0FBQTtBQUFBLElBQy9CLFlBQVksSUFBSyxDQUFBLE9BQUEsRUFBUyxTQUFXLEVBQUEsY0FBQSxDQUFlLE1BQU0sY0FBYztBQUFBLEdBQ3pFLENBQUE7QUFFRCxFQUFBLE1BQU0saUJBQWlCLG1CQUFvQixDQUFBO0FBQUEsSUFDekMsT0FBTyxjQUFlLENBQUEsS0FBQTtBQUFBLElBQ3RCLElBQU0sRUFBQSxVQUFBO0FBQUEsSUFDTixjQUFnQixFQUFBLElBQUE7QUFBQTtBQUFBLElBQ2hCLGFBQWUsRUFBQSxLQUFBO0FBQUEsSUFDZixjQUFn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