@microsoft/windows-admin-center-sdk 2.296.0 → 2.298.1
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/angular/assets/strings/cs-CZ/strings.json +1 -1
- package/angular/assets/strings/de-DE/strings.json +1 -1
- package/angular/assets/strings/es-ES/strings.json +1 -1
- package/angular/assets/strings/fr-FR/strings.json +1 -1
- package/angular/assets/strings/hu-HU/strings.json +1 -1
- package/angular/assets/strings/it-IT/strings.json +1 -1
- package/angular/assets/strings/ja-JP/strings.json +1 -1
- package/angular/assets/strings/ko-KR/strings.json +1 -1
- package/angular/assets/strings/nl-NL/strings.json +1 -1
- package/angular/assets/strings/pl-PL/strings.json +1 -1
- package/angular/assets/strings/pt-BR/strings.json +1 -1
- package/angular/assets/strings/pt-PT/strings.json +1 -1
- package/angular/assets/strings/ru-RU/strings.json +1 -1
- package/angular/assets/strings/strings.json +1 -1
- package/angular/assets/strings/sv-SE/strings.json +1 -1
- package/angular/assets/strings/tr-TR/strings.json +1 -1
- package/angular/assets/strings/zh-CN/strings.json +1 -1
- package/angular/assets/strings/zh-TW/strings.json +1 -1
- package/angular/bundles/microsoft-windows-admin-center-sdk-angular.umd.js +558 -240
- package/angular/bundles/microsoft-windows-admin-center-sdk-angular.umd.js.map +1 -1
- package/angular/bundles/microsoft-windows-admin-center-sdk-angular.umd.min.js +2 -2
- package/angular/bundles/microsoft-windows-admin-center-sdk-angular.umd.min.js.map +1 -1
- package/angular/esm2015/src/controls/actions/containers/action-bar/action-bar.component.js +7 -2
- package/angular/esm2015/src/controls/alert-bar/alert-bar.component.js +5 -5
- package/angular/esm2015/src/controls/common/base.component.js +8 -1
- package/angular/esm2015/src/controls/data-table/data-table.component.js +39 -9
- package/angular/esm2015/src/controls/form/form-field/checklist/checklist-form-field.component.js +11 -8
- package/angular/esm2015/src/controls/form/form-field/combobox/combobox-form-field.component.js +8 -9
- package/angular/esm2015/src/controls/form/form-field/file/file-form-field.component.js +14 -2
- package/angular/esm2015/src/controls/form/form-field/form-field.component.js +9 -2
- package/angular/esm2015/src/controls/layout/layout-definition.component.js +9 -2
- package/angular/esm2015/src/controls/layout/layout.component.js +11 -2
- package/angular/esm2015/src/controls/master-view/master-view.component.js +32 -5
- package/angular/esm2015/src/controls/page-alert-bar/models/index.js +1 -1
- package/angular/esm2015/src/controls/pivot/pivot.component.js +11 -5
- package/angular/esm2015/src/controls/property-grid/property-grid-item.component.js +50 -2
- package/angular/esm2015/src/controls/property-grid/property-grid.component.js +73 -60
- package/angular/esm2015/src/controls/property-grid/property-grid.module.js +5 -1
- package/angular/esm2015/src/controls/settings/common-settings/common-settings.component.js +151 -70
- package/angular/esm2015/src/controls/settings/settings.component.js +48 -8
- package/angular/esm2015/src/controls/settings/settings.module.js +21 -9
- package/angular/esm2015/src/controls/wizard/wizard.component.js +55 -65
- package/angular/esm2015/src/generated/strings.js +1 -1
- package/angular/esm2015/src/service/app-context.service.js +3 -1
- package/angular/fesm2015/microsoft-windows-admin-center-sdk-angular.js +535 -240
- package/angular/fesm2015/microsoft-windows-admin-center-sdk-angular.js.map +1 -1
- package/angular/package.json +2 -0
- package/angular/src/controls/common/base.component.d.ts +5 -0
- package/angular/src/controls/data-table/data-table.component.d.ts +15 -0
- package/angular/src/controls/form/form-field/checklist/checklist-form-field.component.d.ts +1 -0
- package/angular/src/controls/form/form-field/file/file-form-field.component.d.ts +4 -0
- package/angular/src/controls/layout/layout-definition.component.d.ts +6 -1
- package/angular/src/controls/master-view/master-view.component.d.ts +118 -2
- package/angular/src/controls/page-alert-bar/models/index.d.ts +1 -1
- package/angular/src/controls/pivot/pivot.component.d.ts +4 -1
- package/angular/src/controls/property-grid/property-grid-item.component.d.ts +53 -3
- package/angular/src/controls/property-grid/property-grid.component.d.ts +1 -2
- package/angular/src/controls/property-grid/property-grid.module.d.ts +4 -3
- package/angular/src/controls/settings/common-settings/common-settings.component.d.ts +32 -1
- package/angular/src/controls/settings/settings.component.d.ts +18 -1
- package/angular/src/controls/settings/settings.module.d.ts +3 -1
- package/angular/src/generated/strings.d.ts +3 -0
- package/core/base/environment.d.ts +10 -0
- package/core/base/environment.js.map +1 -1
- package/core/data/gateway-connection.d.ts +34 -0
- package/core/data/gateway-connection.js +59 -2
- package/core/data/gateway-connection.js.map +1 -1
- package/core/data/gateway-status.d.ts +24 -0
- package/core/data/gateway-status.js +3 -0
- package/core/data/gateway-status.js.map +1 -0
- package/core/data/node-connection.d.ts +4 -0
- package/core/data/node-connection.js.map +1 -1
- package/core/data/powershell.d.ts +4 -0
- package/core/data/powershell.js +1 -0
- package/core/data/powershell.js.map +1 -1
- package/core/data/wdac-operations.d.ts +123 -0
- package/core/data/wdac-operations.js +144 -0
- package/core/data/wdac-operations.js.map +1 -0
- package/core/diagnostics/sme-web-telemetry-models.d.ts +20 -3
- package/core/diagnostics/sme-web-telemetry-models.js +6 -2
- package/core/diagnostics/sme-web-telemetry-models.js.map +1 -1
- package/core/diagnostics/sme-web-telemetry.d.ts +13 -1
- package/core/diagnostics/sme-web-telemetry.js +51 -11
- package/core/diagnostics/sme-web-telemetry.js.map +1 -1
- package/core/generated/powershell-scripts.d.ts +8 -4
- package/core/generated/powershell-scripts.js +8 -4
- package/core/generated/powershell-scripts.js.map +1 -1
- package/core/index.d.ts +2 -0
- package/core/index.js +1 -0
- package/core/index.js.map +1 -1
- package/core/manifest/environment-modules.js +10 -0
- package/core/manifest/environment-modules.js.map +1 -1
- package/core/notification/powershell-notification.js +1 -1
- package/core/notification/powershell-notification.js.map +1 -1
- package/core/performance/performance-tracker.d.ts +67 -0
- package/core/performance/performance-tracker.js +211 -4
- package/core/performance/performance-tracker.js.map +1 -1
- package/core/rpc/credssp/rpc-credssp-model.d.ts +27 -2
- package/core/rpc/credssp/rpc-credssp-model.js +10 -0
- package/core/rpc/credssp/rpc-credssp-model.js.map +1 -1
- package/core/security/credssp-manager.d.ts +15 -1
- package/core/security/credssp-manager.js +28 -0
- package/core/security/credssp-manager.js.map +1 -1
- package/core/shared/gateway-inventory/gateway-inventory.d.ts +10 -0
- package/core/shared/gateway-inventory/gateway-inventory.js +11 -0
- package/core/shared/gateway-inventory/gateway-inventory.js.map +1 -1
- package/e2e/assets/strings/cs-CZ/strings.json +1 -1
- package/e2e/assets/strings/de-DE/strings.json +1 -1
- package/e2e/assets/strings/es-ES/strings.json +1 -1
- package/e2e/assets/strings/fr-FR/strings.json +1 -1
- package/e2e/assets/strings/hu-HU/strings.json +1 -1
- package/e2e/assets/strings/it-IT/strings.json +1 -1
- package/e2e/assets/strings/ja-JP/strings.json +1 -1
- package/e2e/assets/strings/ko-KR/strings.json +1 -1
- package/e2e/assets/strings/nl-NL/strings.json +1 -1
- package/e2e/assets/strings/pl-PL/strings.json +1 -1
- package/e2e/assets/strings/pt-BR/strings.json +1 -1
- package/e2e/assets/strings/pt-PT/strings.json +1 -1
- package/e2e/assets/strings/ru-RU/strings.json +1 -1
- package/e2e/assets/strings/strings.json +1 -1
- package/e2e/assets/strings/sv-SE/strings.json +1 -1
- package/e2e/assets/strings/tr-TR/strings.json +1 -1
- package/e2e/assets/strings/zh-CN/strings.json +1 -1
- package/e2e/assets/strings/zh-TW/strings.json +1 -1
- package/package.json +5 -3
- package/styles/css/main.css +1 -1
- package/tools/module-template/gulpfile.ts/index.ts +1 -1
- package/tools/package-lock.json +18081 -4110
- package/tools/wac-cli/src/create/main.d.ts +6 -3
- package/tools/wac-cli/src/create/main.js +87 -35
- package/tools/wac-cli/src/create/main.js.map +1 -1
- package/tools/wac-cli/src/index.js +2 -2
- package/tools/wac-cli/src/index.js.map +1 -1
- package/tools/wac-cli/templates/internal/npmrc.txt +6 -0
- package/tools/wac-cli/templates/internal/package.json +101 -0
- package/tools/wac-cli/templates/{manifest/solution-manifest.json → solution/manifest.json} +19 -0
- package/tools/wac-cli/templates/solution/strings.resjson +16 -0
- package/tools/wac-cli/templates/wac-template/angular.json +2 -2
- package/tools/wac-cli/templates/wac-template/gulpfile.ts/config-data.ts +1 -1
- package/tools/wac-cli/templates/wac-template/package.json +0 -8
- package/tools/wac-cli/templates/wac-template/src/app/app-routing.module.ts +1 -1
- package/tools/wac-cli/templates/wac-template/src/main.ts +2 -0
- package/tools/wac-cli/templates/{manifest/tool-manifest.json → wac-template/src/manifest.json} +0 -0
- package/tools/wac-cli/templates/wac-template/src/polyfills.ts +1 -1
- package/tools/wac-cli/templates/wac-template/src/test.ts +2 -2
- package/tools/wac-cli/templates/wac-template/src/version.ts +3 -0
- package/tools/wac-cli/templates/wac-template/version.json +5 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getCLS, getFCP, getFID, getLCP, getTTFB } from 'web-vitals';
|
|
1
2
|
import { Logging } from '../diagnostics/logging';
|
|
2
3
|
import { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry';
|
|
3
4
|
/**
|
|
@@ -5,10 +6,196 @@ import { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry';
|
|
|
5
6
|
*/
|
|
6
7
|
export class SmePerformanceSummary {
|
|
7
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Web Vitals metrics to track. See more details at https://web.dev/vitals/
|
|
11
|
+
*/
|
|
12
|
+
export var WebVitalFields;
|
|
13
|
+
(function (WebVitalFields) {
|
|
14
|
+
WebVitalFields["CLS"] = "CumulativeLayoutShift";
|
|
15
|
+
WebVitalFields["LCP"] = "LargestContentfulPaint";
|
|
16
|
+
WebVitalFields["FCP"] = "FirstContentfulPaint";
|
|
17
|
+
WebVitalFields["FID"] = "FirstInputDelay";
|
|
18
|
+
WebVitalFields["TTFB"] = "TimeToFirstByte";
|
|
19
|
+
WebVitalFields["TBT"] = "TotalBlockingTime";
|
|
20
|
+
WebVitalFields["TTI"] = "TimeToInteractive";
|
|
21
|
+
})(WebVitalFields || (WebVitalFields = {}));
|
|
22
|
+
/**
|
|
23
|
+
* List performance entry types that are relevant for our metrics.
|
|
24
|
+
*/
|
|
25
|
+
export var PerformanceEntryType;
|
|
26
|
+
(function (PerformanceEntryType) {
|
|
27
|
+
PerformanceEntryType["LongTask"] = "longtask";
|
|
28
|
+
PerformanceEntryType["Resource"] = "resource";
|
|
29
|
+
PerformanceEntryType["Mark"] = "mark";
|
|
30
|
+
PerformanceEntryType["Navigation"] = "navigation";
|
|
31
|
+
})(PerformanceEntryType || (PerformanceEntryType = {}));
|
|
32
|
+
/**
|
|
33
|
+
* Simplified performance entry type with only a start time, end time, and entryType.
|
|
34
|
+
*/
|
|
35
|
+
export class TaskTiming {
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Internal further simplification for a range of time with only start and end time.
|
|
39
|
+
*/
|
|
40
|
+
class TimeWindow {
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Performance tracker class handles two things:
|
|
44
|
+
* 1) Tracking lighthouse metrics (see https://web.dev/vitals/)
|
|
45
|
+
* 2) Providing a wrapper to mark various times in code for performance measurement.
|
|
46
|
+
* This is used primarily for shell and various tools to determine load times.
|
|
47
|
+
*/
|
|
8
48
|
export class PerformanceTracker {
|
|
9
49
|
static get smePrefix() {
|
|
10
50
|
return 'SME:';
|
|
11
51
|
}
|
|
52
|
+
static setLighthouseField(field, value) {
|
|
53
|
+
this.lighthouseMetrics[field] = value;
|
|
54
|
+
if (this.lighthouseMetrics.TotalBlockingTime !== null) {
|
|
55
|
+
// if TBT is calculated, we (should) have all required fields, log this in telemetry.
|
|
56
|
+
// It is possible once TBT is calculated other fields can be triggered afterwards (eg CLS or LCP).
|
|
57
|
+
// We will simply update those fields within lighthouse object and send the whole thing.
|
|
58
|
+
// On telemetry end we can decide how to handle (ie take first or last instance).
|
|
59
|
+
SmeWebTelemetry.traceLighthouseData(this.lighthouseMetrics);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Calculate Time to Interactive using list of longtask and resource events. Time to Interactive calculation
|
|
64
|
+
* method can be found at https://web.dev/tti#what-is-tti
|
|
65
|
+
* @param taskList List of all longtask and resource events from current time.
|
|
66
|
+
* @returns Returns time to interactive if it exists, TTI_NOT_FOUND if not.
|
|
67
|
+
*/
|
|
68
|
+
static tryFindTti(taskList) {
|
|
69
|
+
const timestamps = [];
|
|
70
|
+
taskList.forEach((entry) => {
|
|
71
|
+
timestamps.push({ entryType: entry.entryType, time: entry.startTime, isStart: true });
|
|
72
|
+
timestamps.push({ entryType: entry.entryType, time: entry.endTime });
|
|
73
|
+
});
|
|
74
|
+
// push an entry for the current timestamp, so that if the quiet window is at the end
|
|
75
|
+
// (eg mass entries early on, and emptiness later), we can capture the end of the window with this event.
|
|
76
|
+
timestamps.push({ entryType: PerformanceEntryType.LongTask, time: window.performance.now(), isStart: true });
|
|
77
|
+
timestamps.sort((a, b) => a.time < b.time ? -1 : 1);
|
|
78
|
+
const quietWindows = [];
|
|
79
|
+
let startTime = this.fcp;
|
|
80
|
+
let longTaskCount = 0;
|
|
81
|
+
let networkRequestCount = 0;
|
|
82
|
+
// Split ranges into starts and ends, iterate through all timestamps of start/end
|
|
83
|
+
// for each start/end, identify and keep track of long tasks and network requests to identify potential windows
|
|
84
|
+
// isStart means the timestamp is a startTime of a performance entry (long task or resource).
|
|
85
|
+
for (const { entryType, time, isStart } of timestamps) {
|
|
86
|
+
if (isStart) {
|
|
87
|
+
// check if ends current window
|
|
88
|
+
if ((entryType === PerformanceEntryType.LongTask && longTaskCount === 0 && networkRequestCount <= 2) ||
|
|
89
|
+
(entryType === PerformanceEntryType.Resource && longTaskCount === 0 && networkRequestCount === 2)) {
|
|
90
|
+
const newStartTime = startTime ? Math.max(startTime, this.fcp) : this.fcp;
|
|
91
|
+
const endTime = time;
|
|
92
|
+
if (endTime > newStartTime) {
|
|
93
|
+
quietWindows.push({ start: newStartTime, end: endTime });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
if ((entryType === PerformanceEntryType.LongTask && longTaskCount === 1 && networkRequestCount <= 2) ||
|
|
99
|
+
(entryType === PerformanceEntryType.Resource && longTaskCount === 0 && networkRequestCount === 3)) {
|
|
100
|
+
startTime = time;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// For both cases, if we just hit an isStart timestamp, we are starting a new task - increment count depending on type.
|
|
104
|
+
// if not isStart, we are ending a task, decrement count.
|
|
105
|
+
if (entryType === PerformanceEntryType.LongTask) {
|
|
106
|
+
longTaskCount += isStart ? 1 : -1;
|
|
107
|
+
}
|
|
108
|
+
else if (entryType === PerformanceEntryType.Resource) {
|
|
109
|
+
networkRequestCount += isStart ? 1 : -1;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const firstValidWindow = quietWindows.find((window) => (window.end - window.start) >= this.quietWindowLength);
|
|
113
|
+
const relevantLongTasks = taskList.filter((task) => firstValidWindow && task.entryType === PerformanceEntryType.LongTask
|
|
114
|
+
&& task.startTime >= this.fcp && task.endTime <= firstValidWindow.start);
|
|
115
|
+
const timeToInteractiveTimestamp = relevantLongTasks.length > 0
|
|
116
|
+
? relevantLongTasks[relevantLongTasks.length - 1].endTime : this.fcp;
|
|
117
|
+
// if no valid window found, return timeToInteractiveNotFound
|
|
118
|
+
return firstValidWindow ? timeToInteractiveTimestamp : this.timeToInteractiveNotFound;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Initialize interval to calculate time to interactive. TTI will only be calculated if WAC is in non-production mode;
|
|
122
|
+
* b/c calculation itself is non-performant. In production, we will use FID as a proxy for TTI.
|
|
123
|
+
*/
|
|
124
|
+
static tryStartCalculatingTimeToInteractive() {
|
|
125
|
+
if (SmeWebTelemetry.isProduction) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
this.ttiInProgress = true;
|
|
129
|
+
let ttiTrackerCount = 0;
|
|
130
|
+
this.ttiIntervalCheck = setInterval(() => {
|
|
131
|
+
const tti = this.tryFindTti(this.tasks);
|
|
132
|
+
if (tti !== this.timeToInteractiveNotFound) {
|
|
133
|
+
this.setLighthouseField(WebVitalFields.TTI, tti);
|
|
134
|
+
// need to recalculate here because this is dependent on where the TTI is.
|
|
135
|
+
const recalculatedTotalBlockingTime = this.tasks.filter((entry) => entry.entryType === PerformanceEntryType.LongTask).reduce((totalBlockTime, nextEntry) => {
|
|
136
|
+
const duration = nextEntry.endTime - nextEntry.startTime;
|
|
137
|
+
const entrySatisfiesBlockingCriteria = duration > this.totalBlockingTimeThresholdRequirement
|
|
138
|
+
&& nextEntry.endTime < tti
|
|
139
|
+
&& nextEntry.startTime > this.fcp;
|
|
140
|
+
return totalBlockTime + (entrySatisfiesBlockingCriteria ? duration : 0);
|
|
141
|
+
}, 0);
|
|
142
|
+
this.setLighthouseField(WebVitalFields.TBT, recalculatedTotalBlockingTime);
|
|
143
|
+
clearInterval(this.ttiIntervalCheck);
|
|
144
|
+
this.wacPo.disconnect();
|
|
145
|
+
}
|
|
146
|
+
else if (ttiTrackerCount > this.ttiTimeoutThreshold) {
|
|
147
|
+
// if we have gone past threshold and no TTI found,
|
|
148
|
+
// give up on TTI and just search for last long task, we will already have bad score
|
|
149
|
+
const lastLongTask = this.tasks.filter((entry) => entry.entryType === PerformanceEntryType.LongTask).slice(-1)[0];
|
|
150
|
+
this.setLighthouseField(WebVitalFields.TTI, lastLongTask ? lastLongTask.endTime : this.ttiTimeout * this.ttiTimeoutThreshold);
|
|
151
|
+
this.setLighthouseField(WebVitalFields.TBT, this.totalBlockingTime);
|
|
152
|
+
this.wacPo.disconnect();
|
|
153
|
+
clearInterval(this.ttiIntervalCheck);
|
|
154
|
+
}
|
|
155
|
+
++ttiTrackerCount;
|
|
156
|
+
}, this.ttiTimeout);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Initialize web-vitals trackers for all lighthouse metrics.
|
|
160
|
+
*/
|
|
161
|
+
static initializeLighthouseMetricsTrackers() {
|
|
162
|
+
getCLS((item) => this.setLighthouseField(WebVitalFields.CLS, item.value), true);
|
|
163
|
+
getFCP((item) => {
|
|
164
|
+
this.setLighthouseField(WebVitalFields.FCP, item.value);
|
|
165
|
+
this.fcp = item.value;
|
|
166
|
+
this.tryStartCalculatingTimeToInteractive();
|
|
167
|
+
}, true);
|
|
168
|
+
getLCP((item) => this.setLighthouseField(WebVitalFields.LCP, item.value), true);
|
|
169
|
+
getFID((item) => {
|
|
170
|
+
this.setLighthouseField(WebVitalFields.FID, item.value);
|
|
171
|
+
if (!this.ttiInProgress) {
|
|
172
|
+
this.setLighthouseField(WebVitalFields.TBT, this.totalBlockingTime);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
getTTFB((item) => this.setLighthouseField(WebVitalFields.TTFB, item.value));
|
|
176
|
+
// Set a performance observer to collect all the long task and resource events we need to calculate lighthouse metrics.
|
|
177
|
+
this.wacPo = new PerformanceObserver((list) => {
|
|
178
|
+
const entries = list.getEntries();
|
|
179
|
+
for (let i = 0; i < entries.length; ++i) {
|
|
180
|
+
if (entries[i].entryType === PerformanceEntryType.LongTask) {
|
|
181
|
+
// measure TBT as we collect long task events - if using FID, we can just send this accumulated value as is,
|
|
182
|
+
// otherwise can recalculate this later when we find TTI.
|
|
183
|
+
const entrySatisfiesBlockingCriteria = entries[i].duration > this.totalBlockingTimeThresholdRequirement
|
|
184
|
+
&& entries[i].startTime > this.fcp;
|
|
185
|
+
this.totalBlockingTime += entrySatisfiesBlockingCriteria ? entries[i].duration : 0;
|
|
186
|
+
this.tasks.push({ startTime: entries[i].startTime,
|
|
187
|
+
endTime: entries[i].startTime + entries[i].duration,
|
|
188
|
+
entryType: PerformanceEntryType.LongTask });
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
this.tasks.push({ startTime: entries[i].startTime,
|
|
192
|
+
endTime: entries[i].startTime + entries[i].duration,
|
|
193
|
+
entryType: PerformanceEntryType.Resource });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
this.wacPo.observe({ entryTypes: [PerformanceEntryType.LongTask, PerformanceEntryType.Resource] });
|
|
198
|
+
}
|
|
12
199
|
static coreEnvironmentInitStarted() {
|
|
13
200
|
performance.mark(PerformanceTracker.markCoreEnvironmentInitStarted);
|
|
14
201
|
}
|
|
@@ -41,7 +228,7 @@ export class PerformanceTracker {
|
|
|
41
228
|
PerformanceTracker.logAppComponentLoadTime();
|
|
42
229
|
}
|
|
43
230
|
static navigationInitialized() {
|
|
44
|
-
const navigationMarks = performance.getEntriesByType(
|
|
231
|
+
const navigationMarks = performance.getEntriesByType(PerformanceEntryType.Mark)
|
|
45
232
|
.filter(e => e.name.startsWith(PerformanceTracker.smePrefix + 'Navigation'));
|
|
46
233
|
// If we reinitialize navigation, clear all previous navigation marks.
|
|
47
234
|
navigationMarks.forEach(m => { performance.clearMarks(m.name); });
|
|
@@ -147,9 +334,9 @@ export class PerformanceTracker {
|
|
|
147
334
|
totalLoadTime: 0
|
|
148
335
|
};
|
|
149
336
|
/// dont include sme angular navigation marks in the generic data load
|
|
150
|
-
const smeMarks = performance.getEntriesByType(
|
|
337
|
+
const smeMarks = performance.getEntriesByType(PerformanceEntryType.Mark).filter(e => e.name.startsWith(PerformanceTracker.smePrefix)
|
|
151
338
|
&& !e.name.startsWith(PerformanceTracker.smePrefix + 'Navigation'));
|
|
152
|
-
const resourceMarks = performance.getEntriesByType(
|
|
339
|
+
const resourceMarks = performance.getEntriesByType(PerformanceEntryType.Resource);
|
|
153
340
|
smeMarks.forEach(m => {
|
|
154
341
|
data.sme[m.name.replace(PerformanceTracker.smePrefix, '')] = m.startTime;
|
|
155
342
|
performance.clearMarks(m.name);
|
|
@@ -165,7 +352,7 @@ export class PerformanceTracker {
|
|
|
165
352
|
performance.clearMarks(m.name);
|
|
166
353
|
});
|
|
167
354
|
data.totalLoadTime = data.sme[this.markAppComponentInitialized.replace(PerformanceTracker.smePrefix, '')];
|
|
168
|
-
const navigationEntries = performance.getEntriesByType(
|
|
355
|
+
const navigationEntries = performance.getEntriesByType(PerformanceEntryType.Navigation);
|
|
169
356
|
if (navigationEntries && navigationEntries.length) {
|
|
170
357
|
data.navigation = navigationEntries[0];
|
|
171
358
|
}
|
|
@@ -233,5 +420,25 @@ PerformanceTracker.moduleOpening = true;
|
|
|
233
420
|
* Used to keep track of various marks when measuring arbitrary timings.
|
|
234
421
|
*/
|
|
235
422
|
PerformanceTracker.dataLoadMap = {};
|
|
423
|
+
/**
|
|
424
|
+
* Counter for total blocking time on initial loadup. This should be reset every time a new page is initialized.
|
|
425
|
+
*/
|
|
426
|
+
PerformanceTracker.totalBlockingTime = 0;
|
|
427
|
+
// initialize totalBlockingTime as null so we can distinguish when majority of lighthouse metrics are collected
|
|
428
|
+
PerformanceTracker.lighthouseMetrics = { TotalBlockingTime: null };
|
|
429
|
+
PerformanceTracker.fcp = 0;
|
|
430
|
+
PerformanceTracker.tasks = [];
|
|
431
|
+
PerformanceTracker.timeToInteractiveNotFound = -1;
|
|
432
|
+
// Under TTI guidelines, a quiet window is defined to be a 5 second period where no long tasks run and no more than
|
|
433
|
+
// 2 network requests at any given point.
|
|
434
|
+
PerformanceTracker.quietWindowLength = 5000;
|
|
435
|
+
// Time to interactive has to be calculated retroactively - every 10 seconds, we'll calculate and see if we can find TTI.
|
|
436
|
+
// After 20 seconds, cancel and just find current tti (assume a quiet window will appear somewhere in the future)
|
|
437
|
+
// These windows were selected arbitrarily - can be tweaked if necessary.
|
|
438
|
+
PerformanceTracker.ttiTimeout = 10000;
|
|
439
|
+
PerformanceTracker.ttiTimeoutThreshold = 2;
|
|
440
|
+
// Long events (events in excess of 50ms) qualify for total blocking time - any duration in excess of 50ms,
|
|
441
|
+
// the excess time will be added to total blocking time.
|
|
442
|
+
PerformanceTracker.totalBlockingTimeThresholdRequirement = 50;
|
|
236
443
|
|
|
237
444
|
//# sourceMappingURL=performance-tracker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../packages/core/performance/performance-tracker.ts"],"names":[],"mappings":"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","file":"performance-tracker.js","sourcesContent":["import { Logging } from '../diagnostics/logging';\r\nimport { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry';\r\nimport { SmePerformanceData } from '../diagnostics/sme-web-telemetry-models';\r\n\r\n/**\r\n * Summarizes a sequence of measurements\r\n */\r\nexport class SmePerformanceSummary {\r\n label: string;\r\n startTime: number;\r\n totalLoadTime: number;\r\n timestamps: { [index: string]: number };\r\n}\r\n\r\nexport class PerformanceTracker {\r\n public static get smePrefix(): string {\r\n return 'SME:';\r\n }\r\n // indexLoaded is logged by each extension when there index.html file starts executing code\r\n // The value itself is used, not the variable. This is kept here to have a complete list of sme marks used.\r\n private static markIndexLoaded = PerformanceTracker.smePrefix + 'IndexLoaded';\r\n private static markCoreEnvironmentInitStarted = PerformanceTracker.smePrefix + 'CoreEnvironmentInitializeStarted';\r\n private static markCoreEnvironmentInitCompleted = PerformanceTracker.smePrefix + 'CoreEnvironmentInitializeCompleted';\r\n private static markManifestLoadStarted = PerformanceTracker.smePrefix + 'ManifestLoadStarted';\r\n private static markLocalizationStarted = PerformanceTracker.smePrefix + 'LocalizationStarted';\r\n private static markAccessibilityManagerStarted = PerformanceTracker.smePrefix + 'AccessibilityManagerStarted';\r\n private static markAppContextServiceStarted = PerformanceTracker.smePrefix + 'AppContextServiceStarted';\r\n private static markAppContextRpcInitStarted = PerformanceTracker.smePrefix + 'AppContextRpcInitStarted';\r\n private static markAppContextRpcInitComplete = PerformanceTracker.smePrefix + 'AppContextRpcInitComplete';\r\n private static markAppModuleInitialized = PerformanceTracker.smePrefix + 'AppModuleInitialized';\r\n private static markAppComponentInitialized = PerformanceTracker.smePrefix + 'AppComponentInitialized';\r\n\r\n private static markCriticalDataLoaded = PerformanceTracker.smePrefix + 'CriticalDataLoaded';\r\n private static markNavigationInitialized = PerformanceTracker.smePrefix + 'NavigationInitialized';\r\n private static markNavigationStarted = PerformanceTracker.smePrefix + 'NavigationStarted';\r\n private static markNavigationCompleted = PerformanceTracker.smePrefix + 'NavigationCompleted';\r\n private static markNavigationMeasure = PerformanceTracker.smePrefix + 'NavigationMeasure';\r\n\r\n private static moduleOpening = true;\r\n\r\n /**\r\n * Used to keep track of various marks when measuring arbitrary timings.\r\n */\r\n private static dataLoadMap: {[index: string]: PerformanceEntry[]} = {};\r\n\r\n\r\n public static coreEnvironmentInitStarted(): void {\r\n performance.mark(PerformanceTracker.markCoreEnvironmentInitStarted);\r\n }\r\n\r\n public static coreEnvironmentInitCompleted(): void {\r\n performance.mark(PerformanceTracker.markCoreEnvironmentInitCompleted);\r\n }\r\n\r\n public static manifestLoadStarted(): void {\r\n performance.mark(PerformanceTracker.markManifestLoadStarted);\r\n }\r\n\r\n public static localizationStarted(): void {\r\n performance.mark(PerformanceTracker.markLocalizationStarted);\r\n }\r\n\r\n public static accessibilityManagerStarted(): void {\r\n performance.mark(PerformanceTracker.markAccessibilityManagerStarted);\r\n }\r\n\r\n public static appContextServiceStarted(): void {\r\n performance.mark(PerformanceTracker.markAppContextServiceStarted);\r\n }\r\n\r\n public static appContextRpcInitStarted(): void {\r\n performance.mark(PerformanceTracker.markAppContextRpcInitStarted);\r\n }\r\n\r\n public static appContextRpcInitComplete(): void {\r\n performance.mark(PerformanceTracker.markAppContextRpcInitComplete);\r\n }\r\n\r\n public static appModuleInitialized(): void {\r\n performance.mark(PerformanceTracker.markAppModuleInitialized);\r\n }\r\n\r\n public static appComponentInitialized(): void {\r\n performance.mark(PerformanceTracker.markAppComponentInitialized);\r\n PerformanceTracker.logAppComponentLoadTime();\r\n }\r\n\r\n public static navigationInitialized(): void {\r\n const navigationMarks = performance.getEntriesByType('mark')\r\n .filter(e => e.name.startsWith(PerformanceTracker.smePrefix + 'Navigation'));\r\n // If we reinitialize navigation, clear all previous navigation marks.\r\n navigationMarks.forEach(m => { performance.clearMarks(m.name); });\r\n performance.mark(PerformanceTracker.markNavigationInitialized);\r\n }\r\n\r\n public static navigationStarted(): void {\r\n // clear previous marks prior to starting new navigation\r\n performance.clearMarks(PerformanceTracker.markNavigationStarted);\r\n performance.clearMarks(PerformanceTracker.markNavigationCompleted);\r\n\r\n performance.mark(PerformanceTracker.markNavigationStarted);\r\n }\r\n\r\n public static navigationCompleted(moduleOpened: boolean): void {\r\n // clear last measure b/c we are replacing.\r\n performance.clearMeasures(PerformanceTracker.markNavigationMeasure);\r\n\r\n // If the navigation via module open, set this flag so we can treat the criticalLoad differently than normal. We want to\r\n // separate this data b/c some modules have pivot tabs that can also trigger critical data loads multiple times.\r\n this.moduleOpening = moduleOpened;\r\n\r\n performance.mark(PerformanceTracker.markNavigationCompleted);\r\n performance.measure(PerformanceTracker.markNavigationMeasure,\r\n PerformanceTracker.markNavigationStarted,\r\n PerformanceTracker.markNavigationCompleted);\r\n\r\n // clear navigation start/end marks after we measure - only maintain one set of start/end to keep simple.\r\n performance.clearMarks(PerformanceTracker.markNavigationCompleted);\r\n performance.clearMarks(PerformanceTracker.markNavigationStarted);\r\n }\r\n\r\n public static criticalDataLoaded(): void {\r\n performance.mark(PerformanceTracker.markCriticalDataLoaded);\r\n PerformanceTracker.logCriticalDataLoadTime();\r\n }\r\n\r\n /**\r\n * Mark an arbitrary measurement with a label. Clear the previous mark(s) prior to starting new one - allow only one at\r\n * all times.\r\n * @param label The label for the mark and the index for the entry in the internal map.\r\n */\r\n public static markDataLoadStart(label: string) {\r\n const smeLabelString = `${PerformanceTracker.smePrefix}${label}`;\r\n\r\n // If we start, overwrite and clear existing entries.\r\n if (smeLabelString in this.dataLoadMap) {\r\n this.dataLoadMap[smeLabelString].forEach((mark) => {performance.clearMarks(mark.name); });\r\n }\r\n performance.mark(smeLabelString);\r\n // get latest one\r\n const startMark = performance.getEntriesByName(smeLabelString).slice(-1)[0];\r\n\r\n this.dataLoadMap[smeLabelString] = [startMark];\r\n }\r\n\r\n /**\r\n * Mark an arbitrary measurement with a label. Intended to be a midpoint between a start and end.\r\n * @param label The label for the entry in the data map.\r\n * @param specificLabel The label for the mark\r\n */\r\n public static markDataIntermediary(label: string, specificLabel?: string) {\r\n const smeLabelString = `${PerformanceTracker.smePrefix}${label}`;\r\n\r\n if (!(smeLabelString in this.dataLoadMap)) {\r\n return;\r\n }\r\n\r\n const intermediaryLabel = specificLabel ? `${PerformanceTracker.smePrefix}${specificLabel}`\r\n : `${PerformanceTracker.smePrefix}${label}-${this.dataLoadMap[smeLabelString].length + 1}`;\r\n\r\n performance.mark(intermediaryLabel);\r\n\r\n // get latest one\r\n const mark = performance.getEntriesByName(intermediaryLabel).slice(-1)[0];\r\n\r\n this.dataLoadMap[smeLabelString].push(mark);\r\n }\r\n\r\n /**\r\n * Get a summary object from the aggregate data points marked previously.\r\n * @param label The label for the entry in the data map dictionary\r\n * @param specificLabel The label for the new measurement\r\n * @returns The performance summary of the multiple marks.\r\n */\r\n public static markDataLoadEnd(label: string, specificLabel?: string): SmePerformanceSummary {\r\n const smeLabelString = `${PerformanceTracker.smePrefix}${label}`;\r\n\r\n if (!(smeLabelString in this.dataLoadMap)) {\r\n return null;\r\n }\r\n const dataEntry = this.dataLoadMap[smeLabelString];\r\n\r\n const intermediaryLabel = specificLabel ? `${PerformanceTracker.smePrefix}${specificLabel}`\r\n : `${PerformanceTracker.smePrefix}${label}-${dataEntry.length + 1}`;\r\n\r\n performance.mark(intermediaryLabel);\r\n // get latest one\r\n const endMark = performance.getEntriesByName(intermediaryLabel).slice(-1)[0];\r\n dataEntry.push(endMark);\r\n\r\n const startEntry = dataEntry[0];\r\n\r\n const totalLoadTime = endMark.startTime - startEntry.startTime;\r\n\r\n // remove SME prefix here\r\n const summary: SmePerformanceSummary = {\r\n label: label,\r\n timestamps: {},\r\n totalLoadTime: totalLoadTime,\r\n startTime: startEntry.startTime\r\n };\r\n\r\n dataEntry.forEach((mark: PerformanceEntry) => {\r\n performance.clearMarks(mark.name);\r\n summary.timestamps[mark.name.replace(PerformanceTracker.smePrefix, '')] = mark.startTime - startEntry.startTime;\r\n });\r\n\r\n delete this.dataLoadMap[smeLabelString];\r\n return summary;\r\n }\r\n\r\n /**\r\n * Log app component load time - this contains timings up to when the appComponent is loaded.\r\n */\r\n private static logAppComponentLoadTime(): void {\r\n const data: SmePerformanceData = {\r\n sme: {},\r\n resources: {},\r\n navigation: {},\r\n totalLoadTime: 0\r\n };\r\n\r\n /// dont include sme angular navigation marks in the generic data load\r\n const smeMarks = performance.getEntriesByType('mark').filter(e => e.name.startsWith(PerformanceTracker.smePrefix)\r\n && !e.name.startsWith(PerformanceTracker.smePrefix + 'Navigation'));\r\n const resourceMarks = performance.getEntriesByType('resource');\r\n smeMarks.forEach(m => {\r\n data.sme[m.name.replace(PerformanceTracker.smePrefix, '')] = m.startTime;\r\n performance.clearMarks(m.name);\r\n });\r\n resourceMarks.forEach((m: PerformanceResourceTiming) => {\r\n try {\r\n const url = new URL(m.name);\r\n data.resources[url.pathname] = m.duration;\r\n } catch (e) {\r\n data.resources[m.name] = m.duration;\r\n }\r\n performance.clearMarks(m.name);\r\n });\r\n data.totalLoadTime = data.sme[this.markAppComponentInitialized.replace(PerformanceTracker.smePrefix, '')];\r\n const navigationEntries = performance.getEntriesByType('navigation');\r\n if (navigationEntries && navigationEntries.length) {\r\n data.navigation = navigationEntries[0];\r\n }\r\n\r\n SmeWebTelemetry.traceModuleOpenPerformance(data);\r\n }\r\n\r\n /**\r\n * Log critical data load time - this measures the time from angular's startNavigation event to a module to the point at\r\n * which criticalDataLoad() is called, usually in the ngInit of a module\r\n */\r\n private static logCriticalDataLoadTime(): void {\r\n const data: SmePerformanceData = {\r\n sme: {}, totalLoadTime: 0\r\n };\r\n\r\n // If there are multiple somehow, take the latest one\r\n const navigationMeasure = performance.getEntriesByName(PerformanceTracker.markNavigationMeasure).slice(-1)[0];\r\n const criticalData = performance.getEntriesByName(PerformanceTracker.markCriticalDataLoaded).slice(-1)[0];\r\n\r\n // clear performance marks either way - if they exist, we clear them. If not, clear b/c it's faulty data.\r\n performance.clearMeasures(PerformanceTracker.markNavigationMeasure);\r\n performance.clearMarks(PerformanceTracker.markCriticalDataLoaded);\r\n\r\n if (!navigationMeasure || !criticalData) {\r\n Logging.logInformational('PerformanceTracker',\r\n 'Critical data loaded without either criticalData call or navigationMeasure call');\r\n return;\r\n }\r\n data.sme.criticalDataLoadTime = criticalData.startTime - navigationMeasure.startTime;\r\n data.sme.navigationTime = navigationMeasure.duration;\r\n data.totalLoadTime = data.sme.criticalDataLoadTime;\r\n\r\n // If there are multiple somehow, take the latest one\r\n const navInitialized = performance.getEntriesByName(PerformanceTracker.markNavigationInitialized).slice(-1)[0];\r\n if (navInitialized) {\r\n data.sme.timeToFirstNavigateInit = navInitialized.startTime;\r\n data.sme.timeToFirstNavigateStart = navigationMeasure.startTime;\r\n data.sme.timeToFirstNavigateEnd = navigationMeasure.startTime + navigationMeasure.duration;\r\n data.sme.timeToFirstCriticalData = criticalData.startTime;\r\n\r\n data.totalLoadTime = criticalData.startTime; // overwrite if navInit is true.\r\n\r\n performance.clearMarks(navInitialized.name);\r\n }\r\n\r\n if (this.moduleOpening) {\r\n SmeWebTelemetry.traceModuleOpenPerformance(data);\r\n } else {\r\n SmeWebTelemetry.tracePerformanceData(data);\r\n }\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../packages/core/performance/performance-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGnE;;GAEG;AACH,MAAM,OAAO,qBAAqB;CAKjC;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,cAQX;AARD,WAAY,cAAc;IACtB,+CAA6B,CAAA;IAC7B,gDAA8B,CAAA;IAC9B,8CAA4B,CAAA;IAC5B,yCAAuB,CAAA;IACvB,0CAAwB,CAAA;IACxB,2CAAyB,CAAA;IACzB,2CAAyB,CAAA;AAC7B,CAAC,EARW,cAAc,KAAd,cAAc,QAQzB;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,oBAKX;AALD,WAAY,oBAAoB;IAC5B,6CAAqB,CAAA;IACrB,6CAAqB,CAAA;IACrB,qCAAa,CAAA;IACb,iDAAyB,CAAA;AAC7B,CAAC,EALW,oBAAoB,KAApB,oBAAoB,QAK/B;AAED;;GAEG;AACH,MAAM,OAAO,UAAU;CAItB;AAED;;GAEG;AACH,MAAM,UAAU;CAGf;AAED;;;;;GAKG;AACH,MAAM,OAAO,kBAAkB;IACpB,MAAM,KAAK,SAAS;QACvB,OAAO,MAAM,CAAC;IAClB,CAAC;IA0DO,MAAM,CAAC,kBAAkB,CAAC,KAAa,EAAE,KAAa;QAC1D,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QACtC,IAAI,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,KAAK,IAAI,EAAE;YACnD,qFAAqF;YACrF,kGAAkG;YAClG,wFAAwF;YACxF,iFAAiF;YACjF,eAAe,CAAC,mBAAmB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;SAC/D;IACL,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,UAAU,CAAC,QAAsB;QAC3C,MAAM,UAAU,GAAyE,EAAE,CAAC;QAE5F,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACvB,UAAU,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC,CAAC;YACpF,UAAU,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAC,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;QACH,qFAAqF;QACrF,yGAAyG;QACzG,UAAU,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,oBAAoB,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC,CAAC;QAC3G,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEpD,MAAM,YAAY,GAAiB,EAAE,CAAC;QACtC,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC;QACzB,IAAI,aAAa,GAAG,CAAC,CAAC;QACtB,IAAI,mBAAmB,GAAG,CAAC,CAAC;QAC5B,iFAAiF;QACjF,+GAA+G;QAC/G,6FAA6F;QAC7F,KAAK,MAAM,EAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAC,IAAI,UAAU,EAAE;YACjD,IAAI,OAAO,EAAE;gBACT,+BAA+B;gBAC/B,IAAI,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ,IAAI,aAAa,KAAK,CAAC,IAAI,mBAAmB,IAAI,CAAC,CAAC;oBAChG,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ,IAAI,aAAa,KAAK,CAAC,IAAI,mBAAmB,KAAK,CAAC,CAAC,EAAE;oBAC/F,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;oBAC1E,MAAM,OAAO,GAAG,IAAI,CAAC;oBACrB,IAAI,OAAO,GAAG,YAAY,EAAE;wBAAE,YAAY,CAAC,IAAI,CAAE,EAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,OAAO,EAAC,CAAE,CAAC;qBAAE;iBAChG;aACH;iBAAM;gBACJ,IAAI,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ,IAAI,aAAa,KAAK,CAAC,IAAI,mBAAmB,IAAI,CAAC,CAAC;oBAChG,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ,IAAI,aAAa,KAAK,CAAC,IAAI,mBAAmB,KAAK,CAAC,CAAC,EAAE;oBACnG,SAAS,GAAG,IAAI,CAAC;iBACpB;aACJ;YACD,uHAAuH;YACvH,yDAAyD;YACzD,IAAI,SAAS,KAAK,oBAAoB,CAAC,QAAQ,EAAE;gBAC7C,aAAa,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACrC;iBAAM,IAAI,SAAS,KAAK,oBAAoB,CAAC,QAAQ,EAAE;gBACpD,mBAAmB,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aAC3C;SACJ;QAED,MAAM,gBAAgB,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC9G,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,IAAI,IAAI,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ;eACpE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC1H,MAAM,0BAA0B,GAAG,iBAAiB,CAAC,MAAM,GAAG,CAAC;YAC/C,CAAC,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACrF,6DAA6D;QAC7D,OAAO,gBAAgB,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC;IAC1F,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,oCAAoC;QAC9C,IAAI,eAAe,CAAC,YAAY,EAAE;YAC9B,OAAO;SACV;QACD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;YACrC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,GAAG,KAAK,IAAI,CAAC,yBAAyB,EAAE;gBACxC,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBACjD,0EAA0E;gBAC1E,MAAM,6BAA6B,GAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,SAAS,EAAE,EAAE;oBACjH,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,SAAS,CAAC;oBACzD,MAAM,8BAA8B,GAAG,QAAQ,GAAG,IAAI,CAAC,qCAAqC;2BACrD,SAAS,CAAC,OAAO,GAAG,GAAG;2BACvB,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC;oBACtE,OAAO,cAAc,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;gBAC7E,CAAC,EAAE,CAAC,CAAC,CAAC;gBACV,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,6BAA6B,CAAC,CAAC;gBAC3E,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBACrC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;aAC3B;iBAAM,IAAI,eAAe,GAAG,IAAI,CAAC,mBAAmB,EAAE;gBACnD,mDAAmD;gBACnD,oFAAoF;gBACpF,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClH,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EACtC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC;gBACtF,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACpE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;gBACxB,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;aACxC;YACD,EAAE,eAAe,CAAC;QACtB,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,mCAAmC;QAC7C,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QAChF,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACZ,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;YACtB,IAAI,CAAC,oCAAoC,EAAE,CAAC;QAChD,CAAC,EAAE,IAAI,CAAC,CAAC;QACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QAChF,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACZ,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;gBACrB,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;aACvE;QACL,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAE5E,uHAAuH;QACvH,IAAI,CAAC,KAAK,GAAG,IAAI,mBAAmB,CAAC,CAAC,IAAI,EAAE,EAAE;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;gBACrC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,oBAAoB,CAAC,QAAQ,EAAE;oBACxD,4GAA4G;oBAC5G,yDAAyD;oBACzD,MAAM,8BAA8B,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,qCAAqC;2BAChE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC;oBACvE,IAAI,CAAC,iBAAiB,IAAI,8BAA8B,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;oBACnF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;wBAChC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ;wBACnD,SAAS,EAAE,oBAAoB,CAAC,QAAQ,EAAe,CAAC,CAAC;iBAC5E;qBAAM;oBACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;wBAC5C,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ;wBACnD,SAAS,EAAE,oBAAoB,CAAC,QAAQ,EAAe,CAAC,CAAC;iBAChE;aACJ;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAC,UAAU,EAAE,CAAC,oBAAoB,CAAC,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAC,CAAC,CAAC;IACrG,CAAC;IAEM,MAAM,CAAC,0BAA0B;QACpC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,8BAA8B,CAAC,CAAC;IACxE,CAAC;IAEM,MAAM,CAAC,4BAA4B;QACtC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,gCAAgC,CAAC,CAAC;IAC1E,CAAC;IAEM,MAAM,CAAC,mBAAmB;QAC7B,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;IACjE,CAAC;IAEM,MAAM,CAAC,mBAAmB;QAC7B,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;IACjE,CAAC;IAEM,MAAM,CAAC,2BAA2B;QACrC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,+BAA+B,CAAC,CAAC;IACzE,CAAC;IAEM,MAAM,CAAC,wBAAwB;QAClC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,4BAA4B,CAAC,CAAC;IACtE,CAAC;IAEM,MAAM,CAAC,wBAAwB;QAClC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,4BAA4B,CAAC,CAAC;IACtE,CAAC;IAEM,MAAM,CAAC,yBAAyB;QACnC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,6BAA6B,CAAC,CAAC;IACvE,CAAC;IAEM,MAAM,CAAC,oBAAoB;QAC9B,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,wBAAwB,CAAC,CAAC;IAClE,CAAC;IAEM,MAAM,CAAC,uBAAuB;QACjC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,2BAA2B,CAAC,CAAC;QACjE,kBAAkB,CAAC,uBAAuB,EAAE,CAAC;IACjD,CAAC;IAEM,MAAM,CAAC,qBAAqB;QAC/B,MAAM,eAAe,GAAG,WAAW,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,IAAI,CAAC;aAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC;QAChH,sEAAsE;QACtE,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;IACnE,CAAC;IAEM,MAAM,CAAC,iBAAiB;QAC3B,wDAAwD;QACxD,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;QACjE,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;QAEnE,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;IAC/D,CAAC;IAEM,MAAM,CAAC,mBAAmB,CAAC,YAAqB;QACnD,2CAA2C;QAC3C,WAAW,CAAC,aAAa,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;QAEpE,wHAAwH;QACxH,gHAAgH;QAChH,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAElC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;QAC7D,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,qBAAqB,EACxC,kBAAkB,CAAC,qBAAqB,EACxC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;QAEhE,yGAAyG;QACzG,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;QACnE,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;IACrE,CAAC;IAEM,MAAM,CAAC,kBAAkB;QAC5B,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;QAC5D,kBAAkB,CAAC,uBAAuB,EAAE,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,iBAAiB,CAAC,KAAa;QACzC,MAAM,cAAc,GAAG,GAAG,kBAAkB,CAAC,SAAS,GAAG,KAAK,EAAE,CAAC;QAEjE,qDAAqD;QACrD,IAAI,cAAc,IAAI,IAAI,CAAC,WAAW,EAAE;YACpC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,GAAE,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC7F;QACD,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACjC,iBAAiB;QACjB,MAAM,SAAS,GAAG,WAAW,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE5E,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,oBAAoB,CAAC,KAAa,EAAE,aAAsB;QACpE,MAAM,cAAc,GAAI,GAAG,kBAAkB,CAAC,SAAS,GAAG,KAAK,EAAE,CAAC;QAElE,IAAI,CAAC,CAAC,cAAc,IAAI,IAAI,CAAC,WAAW,CAAC,EAAE;YACvC,OAAO;SACV;QAED,MAAM,iBAAiB,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,SAAS,GAAG,aAAa,EAAE;YACnD,CAAC,CAAC,GAAG,kBAAkB,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAEnI,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAEpC,iBAAiB;QACjB,MAAM,IAAI,GAAG,WAAW,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1E,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,eAAe,CAAC,KAAa,EAAE,aAAsB;QAC/D,MAAM,cAAc,GAAI,GAAG,kBAAkB,CAAC,SAAS,GAAG,KAAK,EAAE,CAAC;QAElE,IAAI,CAAC,CAAC,cAAc,IAAI,IAAI,CAAC,WAAW,CAAC,EAAE;YACvC,OAAO,IAAI,CAAC;SACf;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QAEnD,MAAM,iBAAiB,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,SAAS,GAAG,aAAa,EAAE;YACnD,CAAC,CAAC,GAAG,kBAAkB,CAAC,SAAS,GAAG,KAAK,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAE5G,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACpC,iBAAiB;QACjB,MAAM,OAAO,GAAG,WAAW,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7E,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAExB,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAEhC,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;QAE/D,yBAAyB;QACzB,MAAM,OAAO,GAA0B;YACnC,KAAK,EAAE,KAAK;YACZ,UAAU,EAAE,EAAE;YACd,aAAa,EAAE,aAAa;YAC5B,SAAS,EAAE,UAAU,CAAC,SAAS;SAClC,CAAC;QAEF,SAAS,CAAC,OAAO,CAAC,CAAC,IAAsB,EAAE,EAAE;YACzC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;QACpH,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QACxC,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,uBAAuB;QAClC,MAAM,IAAI,GAAuB;YAC7B,GAAG,EAAE,EAAE;YACP,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,EAAE;YACd,aAAa,EAAE,CAAC;SACnB,CAAC;QAEF,sEAAsE;QACtE,MAAM,QAAQ,GAAG,WAAW,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC;eACnE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC;QAClI,MAAM,aAAa,GAAG,WAAW,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAClF,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACjB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC;YACzE,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,aAAa,CAAC,OAAO,CAAC,CAAC,CAA4B,EAAE,EAAE;YACnD,IAAI;gBACA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;aAC7C;YAAC,OAAO,CAAC,EAAE;gBACR,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;aACvC;YACD,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1G,MAAM,iBAAiB,GAAG,WAAW,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;QACxF,IAAI,iBAAiB,IAAI,iBAAiB,CAAC,MAAM,EAAE;YAC/C,IAAI,CAAC,UAAU,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;SAC1C;QAED,eAAe,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;IAED;;;OAGG;IACK,MAAM,CAAC,uBAAuB;QAClC,MAAM,IAAI,GAAuB;YAC7B,GAAG,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC;SAC5B,CAAC;QAEF,qDAAqD;QACrD,MAAM,iBAAiB,GAAG,WAAW,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9G,MAAM,YAAY,GAAG,WAAW,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1G,yGAAyG;QACzG,WAAW,CAAC,aAAa,CAAC,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;QACpE,WAAW,CAAC,UAAU,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;QAElE,IAAI,CAAC,iBAAiB,IAAI,CAAC,YAAY,EAAE;YACrC,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,EACpB,iFAAiF,CAAC,CAAC;YAC5G,OAAO;SACV;QACD,IAAI,CAAC,GAAG,CAAC,oBAAoB,GAAG,YAAY,CAAC,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC;QACrF,IAAI,CAAC,GAAG,CAAC,cAAc,GAAG,iBAAiB,CAAC,QAAQ,CAAC;QACrD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAEnD,qDAAqD;QACrD,MAAM,cAAc,GAAG,WAAW,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/G,IAAI,cAAc,EAAE;YAChB,IAAI,CAAC,GAAG,CAAC,uBAAuB,GAAG,cAAc,CAAC,SAAS,CAAC;YAC5D,IAAI,CAAC,GAAG,CAAC,wBAAwB,GAAG,iBAAiB,CAAC,SAAS,CAAC;YAChE,IAAI,CAAC,GAAG,CAAC,sBAAsB,GAAG,iBAAiB,CAAC,SAAS,GAAG,iBAAiB,CAAC,QAAQ,CAAC;YAC3F,IAAI,CAAC,GAAG,CAAC,uBAAuB,GAAG,YAAY,CAAC,SAAS,CAAC;YAE1D,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,gCAAgC;YAE7E,WAAW,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;SAC/C;QAED,IAAI,IAAI,CAAC,aAAa,EAAE;YACpB,eAAe,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC;SACpD;aAAM;YACH,eAAe,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;SAC9C;IACL,CAAC;;AAvcD,2FAA2F;AAC3F,2GAA2G;AAC5F,kCAAe,GAAG,kBAAkB,CAAC,SAAS,GAAG,aAAa,CAAC;AAC/D,iDAA8B,GAAG,kBAAkB,CAAC,SAAS,GAAG,kCAAkC,CAAC;AACnG,mDAAgC,GAAG,kBAAkB,CAAC,SAAS,GAAG,oCAAoC,CAAC;AACvG,0CAAuB,GAAG,kBAAkB,CAAC,SAAS,GAAG,qBAAqB,CAAC;AAC/E,0CAAuB,GAAG,kBAAkB,CAAC,SAAS,GAAG,qBAAqB,CAAC;AAC/E,kDAA+B,GAAG,kBAAkB,CAAC,SAAS,GAAG,6BAA6B,CAAC;AAC/F,+CAA4B,GAAG,kBAAkB,CAAC,SAAS,GAAG,0BAA0B,CAAC;AACzF,+CAA4B,GAAG,kBAAkB,CAAC,SAAS,GAAG,0BAA0B,CAAC;AACzF,gDAA6B,GAAG,kBAAkB,CAAC,SAAS,GAAG,2BAA2B,CAAC;AAC3F,2CAAwB,GAAG,kBAAkB,CAAC,SAAS,GAAG,sBAAsB,CAAC;AACjF,8CAA2B,GAAG,kBAAkB,CAAC,SAAS,GAAG,yBAAyB,CAAC;AAEvF,yCAAsB,GAAG,kBAAkB,CAAC,SAAS,GAAG,oBAAoB,CAAC;AAC7E,4CAAyB,GAAG,kBAAkB,CAAC,SAAS,GAAG,uBAAuB,CAAC;AACnF,wCAAqB,GAAG,kBAAkB,CAAC,SAAS,GAAG,mBAAmB,CAAC;AAC3E,0CAAuB,GAAG,kBAAkB,CAAC,SAAS,GAAG,qBAAqB,CAAC;AAC/E,wCAAqB,GAAG,kBAAkB,CAAC,SAAS,GAAG,mBAAmB,CAAC;AAE3E,gCAAa,GAAG,IAAI,CAAC;AAEpC;;GAEG;AACY,8BAAW,GAA0C,EAAE,CAAC;AAEvE;;GAEG;AACY,oCAAiB,GAAG,CAAC,CAAC;AAErC,+GAA+G;AAChG,oCAAiB,GAAiC,EAAC,iBAAiB,EAAE,IAAI,EAAC,CAAC;AAI5E,sBAAG,GAAG,CAAC,CAAC;AACR,wBAAK,GAAiB,EAAE,CAAC;AAEjB,4CAAyB,GAAG,CAAC,CAAC,CAAC;AAEtD,mHAAmH;AACnH,yCAAyC;AAClB,oCAAiB,GAAG,IAAI,CAAC;AAEhD,yHAAyH;AACzH,iHAAiH;AACjH,yEAAyE;AAClD,6BAAU,GAAG,KAAK,CAAC;AACnB,sCAAmB,GAAG,CAAC,CAAC;AAE/C,2GAA2G;AAC3G,wDAAwD;AACjC,wDAAqC,GAAG,EAAE,CAAC","file":"performance-tracker.js","sourcesContent":["import { getCLS, getFCP, getFID, getLCP, getTTFB } from 'web-vitals';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry';\r\nimport { LighthousePerformanceMetrics, SmePerformanceData } from '../diagnostics/sme-web-telemetry-models';\r\n\r\n/**\r\n * Summarizes a sequence of measurements\r\n */\r\nexport class SmePerformanceSummary {\r\n label: string;\r\n startTime: number;\r\n totalLoadTime: number;\r\n timestamps: { [index: string]: number };\r\n}\r\n\r\n/**\r\n * Web Vitals metrics to track. See more details at https://web.dev/vitals/\r\n */\r\nexport enum WebVitalFields {\r\n CLS = 'CumulativeLayoutShift',\r\n LCP = 'LargestContentfulPaint',\r\n FCP = 'FirstContentfulPaint',\r\n FID = 'FirstInputDelay',\r\n TTFB = 'TimeToFirstByte',\r\n TBT = 'TotalBlockingTime',\r\n TTI = 'TimeToInteractive',\r\n}\r\n\r\n/**\r\n * List performance entry types that are relevant for our metrics.\r\n */\r\nexport enum PerformanceEntryType {\r\n LongTask = 'longtask',\r\n Resource = 'resource',\r\n Mark = 'mark',\r\n Navigation = 'navigation'\r\n}\r\n\r\n/**\r\n * Simplified performance entry type with only a start time, end time, and entryType.\r\n */\r\nexport class TaskTiming {\r\n startTime: number;\r\n endTime: number;\r\n entryType: PerformanceEntryType;\r\n}\r\n\r\n/**\r\n * Internal further simplification for a range of time with only start and end time.\r\n */\r\nclass TimeWindow {\r\n start: number;\r\n end: number;\r\n}\r\n\r\n/**\r\n * Performance tracker class handles two things:\r\n * 1) Tracking lighthouse metrics (see https://web.dev/vitals/)\r\n * 2) Providing a wrapper to mark various times in code for performance measurement.\r\n * This is used primarily for shell and various tools to determine load times.\r\n */\r\nexport class PerformanceTracker {\r\n public static get smePrefix(): string {\r\n return 'SME:';\r\n }\r\n\r\n // indexLoaded is logged by each extension when there index.html file starts executing code\r\n // The value itself is used, not the variable. This is kept here to have a complete list of sme marks used.\r\n private static markIndexLoaded = PerformanceTracker.smePrefix + 'IndexLoaded';\r\n private static markCoreEnvironmentInitStarted = PerformanceTracker.smePrefix + 'CoreEnvironmentInitializeStarted';\r\n private static markCoreEnvironmentInitCompleted = PerformanceTracker.smePrefix + 'CoreEnvironmentInitializeCompleted';\r\n private static markManifestLoadStarted = PerformanceTracker.smePrefix + 'ManifestLoadStarted';\r\n private static markLocalizationStarted = PerformanceTracker.smePrefix + 'LocalizationStarted';\r\n private static markAccessibilityManagerStarted = PerformanceTracker.smePrefix + 'AccessibilityManagerStarted';\r\n private static markAppContextServiceStarted = PerformanceTracker.smePrefix + 'AppContextServiceStarted';\r\n private static markAppContextRpcInitStarted = PerformanceTracker.smePrefix + 'AppContextRpcInitStarted';\r\n private static markAppContextRpcInitComplete = PerformanceTracker.smePrefix + 'AppContextRpcInitComplete';\r\n private static markAppModuleInitialized = PerformanceTracker.smePrefix + 'AppModuleInitialized';\r\n private static markAppComponentInitialized = PerformanceTracker.smePrefix + 'AppComponentInitialized';\r\n\r\n private static markCriticalDataLoaded = PerformanceTracker.smePrefix + 'CriticalDataLoaded';\r\n private static markNavigationInitialized = PerformanceTracker.smePrefix + 'NavigationInitialized';\r\n private static markNavigationStarted = PerformanceTracker.smePrefix + 'NavigationStarted';\r\n private static markNavigationCompleted = PerformanceTracker.smePrefix + 'NavigationCompleted';\r\n private static markNavigationMeasure = PerformanceTracker.smePrefix + 'NavigationMeasure';\r\n\r\n private static moduleOpening = true;\r\n\r\n /**\r\n * Used to keep track of various marks when measuring arbitrary timings.\r\n */\r\n private static dataLoadMap: {[index: string]: PerformanceEntry[]} = {};\r\n\r\n /**\r\n * Counter for total blocking time on initial loadup. This should be reset every time a new page is initialized.\r\n */\r\n private static totalBlockingTime = 0;\r\n\r\n // initialize totalBlockingTime as null so we can distinguish when majority of lighthouse metrics are collected\r\n private static lighthouseMetrics: LighthousePerformanceMetrics = {TotalBlockingTime: null};\r\n private static ttiIntervalCheck: NodeJS.Timeout;\r\n private static ttiInProgress: boolean;\r\n private static wacPo: PerformanceObserver;\r\n private static fcp = 0;\r\n private static tasks: TaskTiming[] = [];\r\n\r\n public static readonly timeToInteractiveNotFound = -1;\r\n\r\n // Under TTI guidelines, a quiet window is defined to be a 5 second period where no long tasks run and no more than\r\n // 2 network requests at any given point.\r\n public static readonly quietWindowLength = 5000;\r\n\r\n // Time to interactive has to be calculated retroactively - every 10 seconds, we'll calculate and see if we can find TTI.\r\n // After 20 seconds, cancel and just find current tti (assume a quiet window will appear somewhere in the future)\r\n // These windows were selected arbitrarily - can be tweaked if necessary.\r\n public static readonly ttiTimeout = 10000;\r\n public static readonly ttiTimeoutThreshold = 2;\r\n\r\n // Long events (events in excess of 50ms) qualify for total blocking time - any duration in excess of 50ms,\r\n // the excess time will be added to total blocking time.\r\n public static readonly totalBlockingTimeThresholdRequirement = 50;\r\n\r\n private static setLighthouseField(field: string, value: number) {\r\n this.lighthouseMetrics[field] = value;\r\n if (this.lighthouseMetrics.TotalBlockingTime !== null) {\r\n // if TBT is calculated, we (should) have all required fields, log this in telemetry.\r\n // It is possible once TBT is calculated other fields can be triggered afterwards (eg CLS or LCP).\r\n // We will simply update those fields within lighthouse object and send the whole thing.\r\n // On telemetry end we can decide how to handle (ie take first or last instance).\r\n SmeWebTelemetry.traceLighthouseData(this.lighthouseMetrics);\r\n }\r\n }\r\n\r\n /**\r\n * Calculate Time to Interactive using list of longtask and resource events. Time to Interactive calculation\r\n * method can be found at https://web.dev/tti#what-is-tti\r\n * @param taskList List of all longtask and resource events from current time.\r\n * @returns Returns time to interactive if it exists, TTI_NOT_FOUND if not.\r\n */\r\n public static tryFindTti(taskList: TaskTiming[]): number {\r\n const timestamps: {entryType: PerformanceEntryType, time: number, isStart?: boolean}[] = [];\r\n\r\n taskList.forEach((entry) => {\r\n timestamps.push({entryType: entry.entryType, time: entry.startTime, isStart: true});\r\n timestamps.push({entryType: entry.entryType, time: entry.endTime});\r\n });\r\n // push an entry for the current timestamp, so that if the quiet window is at the end\r\n // (eg mass entries early on, and emptiness later), we can capture the end of the window with this event.\r\n timestamps.push({entryType: PerformanceEntryType.LongTask, time: window.performance.now(), isStart: true});\r\n timestamps.sort((a, b) => a.time < b.time ? -1 : 1);\r\n\r\n const quietWindows: TimeWindow[] = [];\r\n let startTime = this.fcp;\r\n let longTaskCount = 0;\r\n let networkRequestCount = 0;\r\n // Split ranges into starts and ends, iterate through all timestamps of start/end\r\n // for each start/end, identify and keep track of long tasks and network requests to identify potential windows\r\n // isStart means the timestamp is a startTime of a performance entry (long task or resource).\r\n for (const {entryType, time, isStart} of timestamps) {\r\n if (isStart) {\r\n // check if ends current window\r\n if ((entryType === PerformanceEntryType.LongTask && longTaskCount === 0 && networkRequestCount <= 2) ||\r\n (entryType === PerformanceEntryType.Resource && longTaskCount === 0 && networkRequestCount === 2)) {\r\n const newStartTime = startTime ? Math.max(startTime, this.fcp) : this.fcp;\r\n const endTime = time;\r\n if (endTime > newStartTime) { quietWindows.push( {start: newStartTime, end: endTime} ); }\r\n }\r\n } else {\r\n if ((entryType === PerformanceEntryType.LongTask && longTaskCount === 1 && networkRequestCount <= 2) ||\r\n (entryType === PerformanceEntryType.Resource && longTaskCount === 0 && networkRequestCount === 3)) {\r\n startTime = time;\r\n }\r\n }\r\n // For both cases, if we just hit an isStart timestamp, we are starting a new task - increment count depending on type.\r\n // if not isStart, we are ending a task, decrement count.\r\n if (entryType === PerformanceEntryType.LongTask) {\r\n longTaskCount += isStart ? 1 : -1;\r\n } else if (entryType === PerformanceEntryType.Resource) {\r\n networkRequestCount += isStart ? 1 : -1;\r\n }\r\n }\r\n\r\n const firstValidWindow = quietWindows.find((window) => (window.end - window.start) >= this.quietWindowLength);\r\n const relevantLongTasks = taskList.filter((task) => firstValidWindow && task.entryType === PerformanceEntryType.LongTask\r\n && task.startTime >= this.fcp && task.endTime <= firstValidWindow.start);\r\n const timeToInteractiveTimestamp = relevantLongTasks.length > 0\r\n ? relevantLongTasks[relevantLongTasks.length - 1].endTime : this.fcp;\r\n // if no valid window found, return timeToInteractiveNotFound\r\n return firstValidWindow ? timeToInteractiveTimestamp : this.timeToInteractiveNotFound;\r\n }\r\n\r\n /**\r\n * Initialize interval to calculate time to interactive. TTI will only be calculated if WAC is in non-production mode;\r\n * b/c calculation itself is non-performant. In production, we will use FID as a proxy for TTI.\r\n */\r\n public static tryStartCalculatingTimeToInteractive(): void {\r\n if (SmeWebTelemetry.isProduction) {\r\n return;\r\n }\r\n this.ttiInProgress = true;\r\n let ttiTrackerCount = 0;\r\n this.ttiIntervalCheck = setInterval(() => {\r\n const tti = this.tryFindTti(this.tasks);\r\n if (tti !== this.timeToInteractiveNotFound) {\r\n this.setLighthouseField(WebVitalFields.TTI, tti);\r\n // need to recalculate here because this is dependent on where the TTI is.\r\n const recalculatedTotalBlockingTime =\r\n this.tasks.filter((entry) => entry.entryType === PerformanceEntryType.LongTask).reduce((totalBlockTime, nextEntry) => {\r\n const duration = nextEntry.endTime - nextEntry.startTime;\r\n const entrySatisfiesBlockingCriteria = duration > this.totalBlockingTimeThresholdRequirement\r\n && nextEntry.endTime < tti\r\n && nextEntry.startTime > this.fcp;\r\n return totalBlockTime + (entrySatisfiesBlockingCriteria ? duration : 0 );\r\n }, 0);\r\n this.setLighthouseField(WebVitalFields.TBT, recalculatedTotalBlockingTime);\r\n clearInterval(this.ttiIntervalCheck);\r\n this.wacPo.disconnect();\r\n } else if (ttiTrackerCount > this.ttiTimeoutThreshold) {\r\n // if we have gone past threshold and no TTI found,\r\n // give up on TTI and just search for last long task, we will already have bad score\r\n const lastLongTask = this.tasks.filter((entry) => entry.entryType === PerformanceEntryType.LongTask).slice(-1)[0];\r\n this.setLighthouseField(WebVitalFields.TTI,\r\n lastLongTask ? lastLongTask.endTime : this.ttiTimeout * this.ttiTimeoutThreshold);\r\n this.setLighthouseField(WebVitalFields.TBT, this.totalBlockingTime);\r\n this.wacPo.disconnect();\r\n clearInterval(this.ttiIntervalCheck);\r\n }\r\n ++ttiTrackerCount;\r\n }, this.ttiTimeout);\r\n }\r\n\r\n /**\r\n * Initialize web-vitals trackers for all lighthouse metrics.\r\n */\r\n public static initializeLighthouseMetricsTrackers(): void {\r\n getCLS((item) => this.setLighthouseField(WebVitalFields.CLS, item.value), true);\r\n getFCP((item) => {\r\n this.setLighthouseField(WebVitalFields.FCP, item.value);\r\n this.fcp = item.value;\r\n this.tryStartCalculatingTimeToInteractive();\r\n }, true);\r\n getLCP((item) => this.setLighthouseField(WebVitalFields.LCP, item.value), true);\r\n getFID((item) => {\r\n this.setLighthouseField(WebVitalFields.FID, item.value);\r\n if (!this.ttiInProgress) {\r\n this.setLighthouseField(WebVitalFields.TBT, this.totalBlockingTime);\r\n }\r\n });\r\n getTTFB((item) => this.setLighthouseField(WebVitalFields.TTFB, item.value));\r\n\r\n // Set a performance observer to collect all the long task and resource events we need to calculate lighthouse metrics.\r\n this.wacPo = new PerformanceObserver((list) => {\r\n const entries = list.getEntries();\r\n\r\n for (let i = 0; i < entries.length; ++i) {\r\n if (entries[i].entryType === PerformanceEntryType.LongTask) {\r\n // measure TBT as we collect long task events - if using FID, we can just send this accumulated value as is,\r\n // otherwise can recalculate this later when we find TTI.\r\n const entrySatisfiesBlockingCriteria = entries[i].duration > this.totalBlockingTimeThresholdRequirement\r\n && entries[i].startTime > this.fcp;\r\n this.totalBlockingTime += entrySatisfiesBlockingCriteria ? entries[i].duration : 0;\r\n this.tasks.push({startTime: entries[i].startTime,\r\n endTime: entries[i].startTime + entries[i].duration,\r\n entryType: PerformanceEntryType.LongTask} as TaskTiming);\r\n } else {\r\n this.tasks.push({startTime: entries[i].startTime,\r\n endTime: entries[i].startTime + entries[i].duration,\r\n entryType: PerformanceEntryType.Resource} as TaskTiming);\r\n }\r\n }\r\n });\r\n\r\n this.wacPo.observe({entryTypes: [PerformanceEntryType.LongTask, PerformanceEntryType.Resource]});\r\n }\r\n\r\n public static coreEnvironmentInitStarted(): void {\r\n performance.mark(PerformanceTracker.markCoreEnvironmentInitStarted);\r\n }\r\n\r\n public static coreEnvironmentInitCompleted(): void {\r\n performance.mark(PerformanceTracker.markCoreEnvironmentInitCompleted);\r\n }\r\n\r\n public static manifestLoadStarted(): void {\r\n performance.mark(PerformanceTracker.markManifestLoadStarted);\r\n }\r\n\r\n public static localizationStarted(): void {\r\n performance.mark(PerformanceTracker.markLocalizationStarted);\r\n }\r\n\r\n public static accessibilityManagerStarted(): void {\r\n performance.mark(PerformanceTracker.markAccessibilityManagerStarted);\r\n }\r\n\r\n public static appContextServiceStarted(): void {\r\n performance.mark(PerformanceTracker.markAppContextServiceStarted);\r\n }\r\n\r\n public static appContextRpcInitStarted(): void {\r\n performance.mark(PerformanceTracker.markAppContextRpcInitStarted);\r\n }\r\n\r\n public static appContextRpcInitComplete(): void {\r\n performance.mark(PerformanceTracker.markAppContextRpcInitComplete);\r\n }\r\n\r\n public static appModuleInitialized(): void {\r\n performance.mark(PerformanceTracker.markAppModuleInitialized);\r\n }\r\n\r\n public static appComponentInitialized(): void {\r\n performance.mark(PerformanceTracker.markAppComponentInitialized);\r\n PerformanceTracker.logAppComponentLoadTime();\r\n }\r\n\r\n public static navigationInitialized(): void {\r\n const navigationMarks = performance.getEntriesByType(PerformanceEntryType.Mark)\r\n .filter(e => e.name.startsWith(PerformanceTracker.smePrefix + 'Navigation'));\r\n // If we reinitialize navigation, clear all previous navigation marks.\r\n navigationMarks.forEach(m => { performance.clearMarks(m.name); });\r\n performance.mark(PerformanceTracker.markNavigationInitialized);\r\n }\r\n\r\n public static navigationStarted(): void {\r\n // clear previous marks prior to starting new navigation\r\n performance.clearMarks(PerformanceTracker.markNavigationStarted);\r\n performance.clearMarks(PerformanceTracker.markNavigationCompleted);\r\n\r\n performance.mark(PerformanceTracker.markNavigationStarted);\r\n }\r\n\r\n public static navigationCompleted(moduleOpened: boolean): void {\r\n // clear last measure b/c we are replacing.\r\n performance.clearMeasures(PerformanceTracker.markNavigationMeasure);\r\n\r\n // If the navigation via module open, set this flag so we can treat the criticalLoad differently than normal. We want to\r\n // separate this data b/c some modules have pivot tabs that can also trigger critical data loads multiple times.\r\n this.moduleOpening = moduleOpened;\r\n\r\n performance.mark(PerformanceTracker.markNavigationCompleted);\r\n performance.measure(PerformanceTracker.markNavigationMeasure,\r\n PerformanceTracker.markNavigationStarted,\r\n PerformanceTracker.markNavigationCompleted);\r\n\r\n // clear navigation start/end marks after we measure - only maintain one set of start/end to keep simple.\r\n performance.clearMarks(PerformanceTracker.markNavigationCompleted);\r\n performance.clearMarks(PerformanceTracker.markNavigationStarted);\r\n }\r\n\r\n public static criticalDataLoaded(): void {\r\n performance.mark(PerformanceTracker.markCriticalDataLoaded);\r\n PerformanceTracker.logCriticalDataLoadTime();\r\n }\r\n\r\n /**\r\n * Mark an arbitrary measurement with a label. Clear the previous mark(s) prior to starting new one - allow only one at\r\n * all times.\r\n * @param label The label for the mark and the index for the entry in the internal map.\r\n */\r\n public static markDataLoadStart(label: string) {\r\n const smeLabelString = `${PerformanceTracker.smePrefix}${label}`;\r\n\r\n // If we start, overwrite and clear existing entries.\r\n if (smeLabelString in this.dataLoadMap) {\r\n this.dataLoadMap[smeLabelString].forEach((mark) => {performance.clearMarks(mark.name); });\r\n }\r\n performance.mark(smeLabelString);\r\n // get latest one\r\n const startMark = performance.getEntriesByName(smeLabelString).slice(-1)[0];\r\n\r\n this.dataLoadMap[smeLabelString] = [startMark];\r\n }\r\n\r\n /**\r\n * Mark an arbitrary measurement with a label. Intended to be a midpoint between a start and end.\r\n * @param label The label for the entry in the data map.\r\n * @param specificLabel The label for the mark\r\n */\r\n public static markDataIntermediary(label: string, specificLabel?: string) {\r\n const smeLabelString = `${PerformanceTracker.smePrefix}${label}`;\r\n\r\n if (!(smeLabelString in this.dataLoadMap)) {\r\n return;\r\n }\r\n\r\n const intermediaryLabel = specificLabel ? `${PerformanceTracker.smePrefix}${specificLabel}`\r\n : `${PerformanceTracker.smePrefix}${label}-${this.dataLoadMap[smeLabelString].length + 1}`;\r\n\r\n performance.mark(intermediaryLabel);\r\n\r\n // get latest one\r\n const mark = performance.getEntriesByName(intermediaryLabel).slice(-1)[0];\r\n\r\n this.dataLoadMap[smeLabelString].push(mark);\r\n }\r\n\r\n /**\r\n * Get a summary object from the aggregate data points marked previously.\r\n * @param label The label for the entry in the data map dictionary\r\n * @param specificLabel The label for the new measurement\r\n * @returns The performance summary of the multiple marks.\r\n */\r\n public static markDataLoadEnd(label: string, specificLabel?: string): SmePerformanceSummary {\r\n const smeLabelString = `${PerformanceTracker.smePrefix}${label}`;\r\n\r\n if (!(smeLabelString in this.dataLoadMap)) {\r\n return null;\r\n }\r\n const dataEntry = this.dataLoadMap[smeLabelString];\r\n\r\n const intermediaryLabel = specificLabel ? `${PerformanceTracker.smePrefix}${specificLabel}`\r\n : `${PerformanceTracker.smePrefix}${label}-${dataEntry.length + 1}`;\r\n\r\n performance.mark(intermediaryLabel);\r\n // get latest one\r\n const endMark = performance.getEntriesByName(intermediaryLabel).slice(-1)[0];\r\n dataEntry.push(endMark);\r\n\r\n const startEntry = dataEntry[0];\r\n\r\n const totalLoadTime = endMark.startTime - startEntry.startTime;\r\n\r\n // remove SME prefix here\r\n const summary: SmePerformanceSummary = {\r\n label: label,\r\n timestamps: {},\r\n totalLoadTime: totalLoadTime,\r\n startTime: startEntry.startTime\r\n };\r\n\r\n dataEntry.forEach((mark: PerformanceEntry) => {\r\n performance.clearMarks(mark.name);\r\n summary.timestamps[mark.name.replace(PerformanceTracker.smePrefix, '')] = mark.startTime - startEntry.startTime;\r\n });\r\n\r\n delete this.dataLoadMap[smeLabelString];\r\n return summary;\r\n }\r\n\r\n /**\r\n * Log app component load time - this contains timings up to when the appComponent is loaded.\r\n */\r\n private static logAppComponentLoadTime(): void {\r\n const data: SmePerformanceData = {\r\n sme: {},\r\n resources: {},\r\n navigation: {},\r\n totalLoadTime: 0\r\n };\r\n\r\n /// dont include sme angular navigation marks in the generic data load\r\n const smeMarks = performance.getEntriesByType(PerformanceEntryType.Mark).filter(e => e.name.startsWith(PerformanceTracker.smePrefix)\r\n && !e.name.startsWith(PerformanceTracker.smePrefix + 'Navigation'));\r\n const resourceMarks = performance.getEntriesByType(PerformanceEntryType.Resource);\r\n smeMarks.forEach(m => {\r\n data.sme[m.name.replace(PerformanceTracker.smePrefix, '')] = m.startTime;\r\n performance.clearMarks(m.name);\r\n });\r\n resourceMarks.forEach((m: PerformanceResourceTiming) => {\r\n try {\r\n const url = new URL(m.name);\r\n data.resources[url.pathname] = m.duration;\r\n } catch (e) {\r\n data.resources[m.name] = m.duration;\r\n }\r\n performance.clearMarks(m.name);\r\n });\r\n data.totalLoadTime = data.sme[this.markAppComponentInitialized.replace(PerformanceTracker.smePrefix, '')];\r\n const navigationEntries = performance.getEntriesByType(PerformanceEntryType.Navigation);\r\n if (navigationEntries && navigationEntries.length) {\r\n data.navigation = navigationEntries[0];\r\n }\r\n\r\n SmeWebTelemetry.traceModuleOpenPerformance(data);\r\n }\r\n\r\n /**\r\n * Log critical data load time - this measures the time from angular's startNavigation event to a module to the point at\r\n * which criticalDataLoad() is called, usually in the ngInit of a module\r\n */\r\n private static logCriticalDataLoadTime(): void {\r\n const data: SmePerformanceData = {\r\n sme: {}, totalLoadTime: 0\r\n };\r\n\r\n // If there are multiple somehow, take the latest one\r\n const navigationMeasure = performance.getEntriesByName(PerformanceTracker.markNavigationMeasure).slice(-1)[0];\r\n const criticalData = performance.getEntriesByName(PerformanceTracker.markCriticalDataLoaded).slice(-1)[0];\r\n\r\n // clear performance marks either way - if they exist, we clear them. If not, clear b/c it's faulty data.\r\n performance.clearMeasures(PerformanceTracker.markNavigationMeasure);\r\n performance.clearMarks(PerformanceTracker.markCriticalDataLoaded);\r\n\r\n if (!navigationMeasure || !criticalData) {\r\n Logging.logInformational('PerformanceTracker',\r\n 'Critical data loaded without either criticalData call or navigationMeasure call');\r\n return;\r\n }\r\n data.sme.criticalDataLoadTime = criticalData.startTime - navigationMeasure.startTime;\r\n data.sme.navigationTime = navigationMeasure.duration;\r\n data.totalLoadTime = data.sme.criticalDataLoadTime;\r\n\r\n // If there are multiple somehow, take the latest one\r\n const navInitialized = performance.getEntriesByName(PerformanceTracker.markNavigationInitialized).slice(-1)[0];\r\n if (navInitialized) {\r\n data.sme.timeToFirstNavigateInit = navInitialized.startTime;\r\n data.sme.timeToFirstNavigateStart = navigationMeasure.startTime;\r\n data.sme.timeToFirstNavigateEnd = navigationMeasure.startTime + navigationMeasure.duration;\r\n data.sme.timeToFirstCriticalData = criticalData.startTime;\r\n\r\n data.totalLoadTime = criticalData.startTime; // overwrite if navInit is true.\r\n\r\n performance.clearMarks(navInitialized.name);\r\n }\r\n\r\n if (this.moduleOpening) {\r\n SmeWebTelemetry.traceModuleOpenPerformance(data);\r\n } else {\r\n SmeWebTelemetry.tracePerformanceData(data);\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NodeRequestOptions } from '../../data/node-connection';
|
|
1
2
|
import { RpcBaseData } from '../rpc-base';
|
|
2
3
|
/**
|
|
3
4
|
* CredSSP request Rpc call name and version.
|
|
@@ -29,6 +30,16 @@ export interface ConfigurationStatus {
|
|
|
29
30
|
client?: ClientRoleConfiguration;
|
|
30
31
|
servers?: ServerRoleConfiguration[];
|
|
31
32
|
}
|
|
33
|
+
export interface GatewayLocalPowerShellConfig {
|
|
34
|
+
/**
|
|
35
|
+
* Server configured for executing cluster operations.
|
|
36
|
+
*/
|
|
37
|
+
configuredServerConnectionString: string;
|
|
38
|
+
/**
|
|
39
|
+
* PowerShell session options to run with cluster operations.
|
|
40
|
+
*/
|
|
41
|
+
powerShellOptions: NodeRequestOptions;
|
|
42
|
+
}
|
|
32
43
|
/**
|
|
33
44
|
* Identifies the CredSSP operation type to preform
|
|
34
45
|
*/
|
|
@@ -72,7 +83,13 @@ export declare enum RpcCredSSPOperationType {
|
|
|
72
83
|
* Confirm the CredSSP client configuration on the gateway, and confirm the CredSSP server
|
|
73
84
|
* configuration to the managed server.
|
|
74
85
|
*/
|
|
75
|
-
ConfirmDelegation = 8
|
|
86
|
+
ConfirmDelegation = 8,
|
|
87
|
+
/**
|
|
88
|
+
* Configure CredSSP server role on a given server and enable gateway to delegate to managed server
|
|
89
|
+
* if gateway machine is not given. Otherwise, do nothing. Return configured server name and
|
|
90
|
+
* PowerShell options needed for proceeding invoke PowerShell calls.
|
|
91
|
+
*/
|
|
92
|
+
TryGatewayLocalPowerShellConfig = 9
|
|
76
93
|
}
|
|
77
94
|
/**
|
|
78
95
|
* Explicit credentials i.e username andd password
|
|
@@ -134,6 +151,10 @@ export interface RpcCredSSPOperationResult {
|
|
|
134
151
|
* Solution to error if any.
|
|
135
152
|
*/
|
|
136
153
|
solutionMessage?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Data to return if any.
|
|
156
|
+
*/
|
|
157
|
+
data?: GatewayLocalPowerShellConfig;
|
|
137
158
|
/**
|
|
138
159
|
* CredSSP configuration information of the client/server.
|
|
139
160
|
*/
|
|
@@ -150,5 +171,9 @@ export declare enum RpcCredSSPOperationResultMember {
|
|
|
150
171
|
/**
|
|
151
172
|
* "configurationData" member of operation result interface.
|
|
152
173
|
*/
|
|
153
|
-
ConfigurationStatus = "configurationStatus"
|
|
174
|
+
ConfigurationStatus = "configurationStatus",
|
|
175
|
+
/**
|
|
176
|
+
* "data" member of operation result interface.
|
|
177
|
+
*/
|
|
178
|
+
Data = "data"
|
|
154
179
|
}
|
|
@@ -57,6 +57,12 @@ export var RpcCredSSPOperationType;
|
|
|
57
57
|
* configuration to the managed server.
|
|
58
58
|
*/
|
|
59
59
|
RpcCredSSPOperationType[RpcCredSSPOperationType["ConfirmDelegation"] = 8] = "ConfirmDelegation";
|
|
60
|
+
/**
|
|
61
|
+
* Configure CredSSP server role on a given server and enable gateway to delegate to managed server
|
|
62
|
+
* if gateway machine is not given. Otherwise, do nothing. Return configured server name and
|
|
63
|
+
* PowerShell options needed for proceeding invoke PowerShell calls.
|
|
64
|
+
*/
|
|
65
|
+
RpcCredSSPOperationType[RpcCredSSPOperationType["TryGatewayLocalPowerShellConfig"] = 9] = "TryGatewayLocalPowerShellConfig";
|
|
60
66
|
})(RpcCredSSPOperationType || (RpcCredSSPOperationType = {}));
|
|
61
67
|
/**
|
|
62
68
|
* CredSSP operation result returnable members.
|
|
@@ -71,6 +77,10 @@ export var RpcCredSSPOperationResultMember;
|
|
|
71
77
|
* "configurationData" member of operation result interface.
|
|
72
78
|
*/
|
|
73
79
|
RpcCredSSPOperationResultMember["ConfigurationStatus"] = "configurationStatus";
|
|
80
|
+
/**
|
|
81
|
+
* "data" member of operation result interface.
|
|
82
|
+
*/
|
|
83
|
+
RpcCredSSPOperationResultMember["Data"] = "data";
|
|
74
84
|
})(RpcCredSSPOperationResultMember || (RpcCredSSPOperationResultMember = {}));
|
|
75
85
|
|
|
76
86
|
//# sourceMappingURL=rpc-credssp-model.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../packages/core/rpc/credssp/rpc-credssp-model.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../packages/core/rpc/credssp/rpc-credssp-model.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,oBAAoB;;AACf,4BAAO,GAAG,gBAAgB,CAAC;AAC3B,4BAAO,GAAG,OAAO,CAAC;AAGpC;;GAEG;AACH,MAAM,OAAO,qBAAqB;;AAChB,6BAAO,GAAG,SAAS,CAAC;AACpB,6BAAO,GAAG,OAAO,CAAC;AAkCpC;;GAEG;AACH,MAAM,CAAN,IAAY,uBAuDX;AAvDD,WAAY,uBAAuB;IAC/B;;OAEG;IACH,mGAAuB,CAAA;IAEvB;;OAEG;IACH,qGAAwB,CAAA;IAExB;;OAEG;IACH,6FAAoB,CAAA;IAEpB;;OAEG;IACH,+FAAqB,CAAA;IAErB;;;OAGG;IACH,6FAAoB,CAAA;IAEpB;;;OAGG;IACH,mFAAe,CAAA;IAEf;;;OAGG;IACH,iHAA8B,CAAA;IAE9B;;OAEG;IACH,+HAAqC,CAAA;IAErC;;;OAGG;IACH,+FAAqB,CAAA;IACrB;;;;OAIG;IACH,2HAAmC,CAAA;AACvC,CAAC,EAvDW,uBAAuB,KAAvB,uBAAuB,QAuDlC;AAoFD;;GAEG;AACH,MAAM,CAAN,IAAY,+BAeX;AAfD,WAAY,+BAA+B;IACvC;;OAEG;IACH,0DAAuB,CAAA;IAEvB;;OAEG;IACH,8EAA2C,CAAA;IAE3C;;OAEG;IACH,gDAAa,CAAA;AACjB,CAAC,EAfW,+BAA+B,KAA/B,+BAA+B,QAe1C","file":"rpc-credssp-model.js","sourcesContent":["import { NodeRequestOptions } from '../../data/node-connection';\r\nimport { RpcBaseData } from '../rpc-base';\r\n\r\n/**\r\n * CredSSP request Rpc call name and version.\r\n */\r\nexport class RpcCredSspRequestKey {\r\n public static command = 'CredSspRequest';\r\n public static version = '0.1.0';\r\n}\r\n\r\n/**\r\n * CredSSP response Rpc call name and version\r\n */\r\nexport class RpcCredSspResponseKey {\r\n public static command = 'CredSsp';\r\n public static version = '0.1.0';\r\n}\r\n\r\nexport interface ServerRoleConfiguration {\r\n ServerName: string;\r\n IsServerConfiguredAsServerRole: boolean;\r\n}\r\n\r\nexport interface ClientRoleConfiguration {\r\n IsGatewayConfiguredAsClientRole: boolean;\r\n AllowFreshCredentialsKeyPresent: boolean;\r\n AllowFreshCredentialsWhenNTLMOnlyKeyPresent: boolean;\r\n AllowFreshCredentialsDelegatableServers: string[];\r\n AllowFreshCredentialsWhenNTLMOnlyDelegatableServers: string[];\r\n NotDelegatableServers: string[];\r\n}\r\n\r\nexport interface ConfigurationStatus {\r\n client?: ClientRoleConfiguration;\r\n servers?: ServerRoleConfiguration[];\r\n}\r\n\r\nexport interface GatewayLocalPowerShellConfig {\r\n /**\r\n * Server configured for executing cluster operations.\r\n */\r\n configuredServerConnectionString: string;\r\n\r\n /**\r\n * PowerShell session options to run with cluster operations.\r\n */\r\n powerShellOptions: NodeRequestOptions;\r\n}\r\n\r\n/**\r\n * Identifies the CredSSP operation type to preform\r\n */\r\nexport enum RpcCredSSPOperationType {\r\n /**\r\n * Enable CredSSP Server role on the managed server.\r\n */\r\n EnableManagedServer = 0,\r\n\r\n /**\r\n * Disable CredSSP Server role on the managed server.\r\n */\r\n DisableManagedServer = 1,\r\n\r\n /**\r\n * Enable CredSSP client role on the gateway and delegate to the list ot servers.\r\n */\r\n EnableClientRole = 2,\r\n\r\n /**\r\n * Disable CredSSP client role on the gateway and remove all delegated servers.\r\n */\r\n DisableClientRole = 3,\r\n\r\n /**\r\n * Enable CredSSP Server role on the managed server, and enable the gateway to\r\n * delegate to the managed server.\r\n */\r\n EnableDelegation = 4,\r\n\r\n /**\r\n * Test that CredSSP connection from gateway to server(s) is enabled. To function as verification mechanism\r\n * that CredSSP is bound to work.\r\n */\r\n TestCredSSP = 5,\r\n\r\n /**\r\n * Confirm the CredSSP client configuration on the gateway machine and the list of servers\r\n * that can be delegated fresh credentials from the gateway.\r\n */\r\n ConfirmClientConfiguration = 6,\r\n\r\n /**\r\n * Confirm the CredSSP server configuration on the managed server.\r\n */\r\n ConfirmManagedServerConfiguration = 7,\r\n\r\n /**\r\n * Confirm the CredSSP client configuration on the gateway, and confirm the CredSSP server\r\n * configuration to the managed server.\r\n */\r\n ConfirmDelegation = 8,\r\n /**\r\n * Configure CredSSP server role on a given server and enable gateway to delegate to managed server\r\n * if gateway machine is not given. Otherwise, do nothing. Return configured server name and\r\n * PowerShell options needed for proceeding invoke PowerShell calls.\r\n */\r\n TryGatewayLocalPowerShellConfig = 9\r\n}\r\n\r\n/**\r\n * Explicit credentials i.e username andd password\r\n */\r\nexport interface Credentials {\r\n username: string;\r\n password: string;\r\n}\r\n\r\n/**\r\n * CredSSP Manager operation/action RPC message.\r\n */\r\nexport interface RpcCredSSPOperation extends RpcBaseData {\r\n /**\r\n * Request specific Id to track completion.\r\n */\r\n requestId: string;\r\n\r\n /**\r\n * Type of CredSSP operation to perform\r\n */\r\n operation: RpcCredSSPOperationType;\r\n\r\n /**\r\n * @deprecated\r\n * The contextual scenario title to be used when showing notifications.\r\n */\r\n notificationTitle: string;\r\n\r\n /**\r\n * The server names to use in this request. Can be a single server for role server\r\n * or a list of servers for role client.\r\n */\r\n serverNames: string[];\r\n\r\n /***\r\n * Authentication options, need the username and password here\r\n */\r\n credentials?: Credentials;\r\n\r\n /**\r\n * @deprecated\r\n * Optional notification Id to be used when showing notifications. This will allow notifications\r\n * from the caller and from CredSSP to be merged in the notification center.\r\n */\r\n notificationId?: string;\r\n}\r\n\r\n/**\r\n * CredSSP Manager operation/action RPC message result.\r\n */\r\nexport interface RpcCredSSPOperationResult {\r\n /**\r\n * Request specific Id to track completion.\r\n */\r\n requestId: string;\r\n\r\n /**\r\n * Did the requested operation succeed or not?\r\n */\r\n succeeded: boolean;\r\n\r\n /**\r\n * Error message if any.\r\n */\r\n error?: string;\r\n\r\n /**\r\n * Solution to error if any.\r\n */\r\n solutionMessage?: string;\r\n\r\n /**\r\n * Data to return if any.\r\n */\r\n data?: GatewayLocalPowerShellConfig;\r\n\r\n /**\r\n * CredSSP configuration information of the client/server.\r\n */\r\n configurationStatus?: ConfigurationStatus;\r\n}\r\n\r\n/**\r\n * CredSSP operation result returnable members.\r\n */\r\nexport enum RpcCredSSPOperationResultMember {\r\n /**\r\n * \"Succeeded\" member of operation result interface.\r\n */\r\n Succeeded = 'succeeded',\r\n\r\n /**\r\n * \"configurationData\" member of operation result interface.\r\n */\r\n ConfigurationStatus = 'configurationStatus',\r\n\r\n /**\r\n * \"data\" member of operation result interface.\r\n */\r\n Data = 'data'\r\n}\r\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
|
-
import { ClientRoleConfiguration, ConfigurationStatus, Credentials, ServerRoleConfiguration } from '../rpc/credssp/rpc-credssp-model';
|
|
2
|
+
import { ClientRoleConfiguration, ConfigurationStatus, Credentials, GatewayLocalPowerShellConfig, ServerRoleConfiguration } from '../rpc/credssp/rpc-credssp-model';
|
|
3
3
|
import { Rpc } from '../rpc/rpc';
|
|
4
4
|
/**
|
|
5
5
|
* CredSPP Manager class. Handles detecting and configuring CredSSP on a set of servers.
|
|
@@ -43,12 +43,26 @@ export declare class CredSSPManager {
|
|
|
43
43
|
*/
|
|
44
44
|
wsmanDisableClientRole(serverNames: string[], verbose?: boolean): Observable<boolean>;
|
|
45
45
|
/**
|
|
46
|
+
* @deprecated
|
|
47
|
+
* Use tryGatewayLocalPowershellConfig instead which will only enable CredSSP when the gateway is making
|
|
48
|
+
* a double hop to a remote node. This method will enable CredSSP every time, even in cases where
|
|
49
|
+
* it is not needed.
|
|
50
|
+
*
|
|
46
51
|
* New Enable the server as a CredSSP server, and enable the gateway as a CredSSP client of the server.
|
|
47
52
|
*
|
|
48
53
|
* @param serverName The server where CredSSP delegation should be enabled
|
|
49
54
|
* @param verbose (Optional) Specify whether a solution (if any) should be returned if CredSSP errored
|
|
50
55
|
*/
|
|
51
56
|
wsmanEnableDelegation(serverName: string, verbose?: boolean): Observable<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Check to see if given servers contain the gateway machine. If not, enable CredSSP, otherwise, do nothing.
|
|
59
|
+
*
|
|
60
|
+
* @param serverNames String array of server names to check for a match with the gateway server name.
|
|
61
|
+
* If not found, CredSSP will be enabled between the gateway machine and the server name at index 0.
|
|
62
|
+
* @param verbose (Optional) Specify whether a solution (if any) should be returned if CredSSP errored.
|
|
63
|
+
* @returns GatewayLocalPowerShellConfig object if success, null otherwise.
|
|
64
|
+
*/
|
|
65
|
+
tryGatewayLocalPowerShellConfig(serverNames: string[], verbose?: boolean): Observable<GatewayLocalPowerShellConfig>;
|
|
52
66
|
/**
|
|
53
67
|
* Test WSMan CredSSP connection from gateway to server(s)
|
|
54
68
|
*
|
|
@@ -108,6 +108,11 @@ export class CredSSPManager {
|
|
|
108
108
|
}, verbose, RpcCredSSPOperationResultMember.Succeeded);
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
|
+
* @deprecated
|
|
112
|
+
* Use tryGatewayLocalPowershellConfig instead which will only enable CredSSP when the gateway is making
|
|
113
|
+
* a double hop to a remote node. This method will enable CredSSP every time, even in cases where
|
|
114
|
+
* it is not needed.
|
|
115
|
+
*
|
|
111
116
|
* New Enable the server as a CredSSP server, and enable the gateway as a CredSSP client of the server.
|
|
112
117
|
*
|
|
113
118
|
* @param serverName The server where CredSSP delegation should be enabled
|
|
@@ -128,6 +133,29 @@ export class CredSSPManager {
|
|
|
128
133
|
notificationId: null
|
|
129
134
|
}, verbose, RpcCredSSPOperationResultMember.Succeeded);
|
|
130
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Check to see if given servers contain the gateway machine. If not, enable CredSSP, otherwise, do nothing.
|
|
138
|
+
*
|
|
139
|
+
* @param serverNames String array of server names to check for a match with the gateway server name.
|
|
140
|
+
* If not found, CredSSP will be enabled between the gateway machine and the server name at index 0.
|
|
141
|
+
* @param verbose (Optional) Specify whether a solution (if any) should be returned if CredSSP errored.
|
|
142
|
+
* @returns GatewayLocalPowerShellConfig object if success, null otherwise.
|
|
143
|
+
*/
|
|
144
|
+
tryGatewayLocalPowerShellConfig(serverNames, verbose = false) {
|
|
145
|
+
if (this.rpc.isShell) {
|
|
146
|
+
throw new Error('Not supported on the shell environment.');
|
|
147
|
+
}
|
|
148
|
+
if (serverNames.length === 0 || serverNames.some(serverName => MsftSme.isNullOrWhiteSpace(serverName))) {
|
|
149
|
+
throw new Error('The server name(s) must be provided.');
|
|
150
|
+
}
|
|
151
|
+
return this.sendRequest({
|
|
152
|
+
requestId: MsftSme.getUniqueId(),
|
|
153
|
+
operation: RpcCredSSPOperationType.TryGatewayLocalPowerShellConfig,
|
|
154
|
+
serverNames: serverNames,
|
|
155
|
+
notificationTitle: null,
|
|
156
|
+
notificationId: null
|
|
157
|
+
}, verbose, RpcCredSSPOperationResultMember.Data);
|
|
158
|
+
}
|
|
131
159
|
/**
|
|
132
160
|
* Test WSMan CredSSP connection from gateway to server(s)
|
|
133
161
|
*
|