@pax8-cta/core 0.1.0
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/LICENSE +198 -0
- package/dist/auth/device-code-login.d.ts +40 -0
- package/dist/auth/device-code-login.d.ts.map +1 -0
- package/dist/auth/device-code-login.js +59 -0
- package/dist/auth/device-code-login.js.map +1 -0
- package/dist/auth/gdap-client.d.ts +81 -0
- package/dist/auth/gdap-client.d.ts.map +1 -0
- package/dist/auth/gdap-client.js +128 -0
- package/dist/auth/gdap-client.js.map +1 -0
- package/dist/auth/index.d.ts +19 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +19 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/token-manager.d.ts +54 -0
- package/dist/auth/token-manager.d.ts.map +1 -0
- package/dist/auth/token-manager.js +150 -0
- package/dist/auth/token-manager.js.map +1 -0
- package/dist/client.d.ts +27 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +27 -0
- package/dist/client.js.map +1 -0
- package/dist/config/client.d.ts +24 -0
- package/dist/config/client.d.ts.map +1 -0
- package/dist/config/client.js +18 -0
- package/dist/config/client.js.map +1 -0
- package/dist/config/index.d.ts +18 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +18 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +81 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +271 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +751 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +556 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/constants.d.ts +116 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +170 -0
- package/dist/constants.js.map +1 -0
- package/dist/dataverse/agent-resolver.d.ts +98 -0
- package/dist/dataverse/agent-resolver.d.ts.map +1 -0
- package/dist/dataverse/agent-resolver.js +185 -0
- package/dist/dataverse/agent-resolver.js.map +1 -0
- package/dist/dataverse/client.d.ts +104 -0
- package/dist/dataverse/client.d.ts.map +1 -0
- package/dist/dataverse/client.js +272 -0
- package/dist/dataverse/client.js.map +1 -0
- package/dist/dataverse/connection-refs.d.ts +115 -0
- package/dist/dataverse/connection-refs.d.ts.map +1 -0
- package/dist/dataverse/connection-refs.js +203 -0
- package/dist/dataverse/connection-refs.js.map +1 -0
- package/dist/dataverse/index.d.ts +20 -0
- package/dist/dataverse/index.d.ts.map +1 -0
- package/dist/dataverse/index.js +20 -0
- package/dist/dataverse/index.js.map +1 -0
- package/dist/dataverse/solution-ops.d.ts +100 -0
- package/dist/dataverse/solution-ops.d.ts.map +1 -0
- package/dist/dataverse/solution-ops.js +288 -0
- package/dist/dataverse/solution-ops.js.map +1 -0
- package/dist/errors.d.ts +171 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +178 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/mock/demo-data.d.ts +213 -0
- package/dist/mock/demo-data.d.ts.map +1 -0
- package/dist/mock/demo-data.js +1096 -0
- package/dist/mock/demo-data.js.map +1 -0
- package/dist/mock/demo-deployment-store.d.ts +77 -0
- package/dist/mock/demo-deployment-store.d.ts.map +1 -0
- package/dist/mock/demo-deployment-store.js +85 -0
- package/dist/mock/demo-deployment-store.js.map +1 -0
- package/dist/powerplatform/admin-client.d.ts +226 -0
- package/dist/powerplatform/admin-client.d.ts.map +1 -0
- package/dist/powerplatform/admin-client.js +315 -0
- package/dist/powerplatform/admin-client.js.map +1 -0
- package/dist/powerplatform/index.d.ts +18 -0
- package/dist/powerplatform/index.d.ts.map +1 -0
- package/dist/powerplatform/index.js +18 -0
- package/dist/powerplatform/index.js.map +1 -0
- package/dist/powerplatform/tenant-discovery.d.ts +100 -0
- package/dist/powerplatform/tenant-discovery.d.ts.map +1 -0
- package/dist/powerplatform/tenant-discovery.js +205 -0
- package/dist/powerplatform/tenant-discovery.js.map +1 -0
- package/dist/preconditions/check.d.ts +41 -0
- package/dist/preconditions/check.d.ts.map +1 -0
- package/dist/preconditions/check.js +173 -0
- package/dist/preconditions/check.js.map +1 -0
- package/dist/preconditions/index.d.ts +20 -0
- package/dist/preconditions/index.d.ts.map +1 -0
- package/dist/preconditions/index.js +20 -0
- package/dist/preconditions/index.js.map +1 -0
- package/dist/preconditions/loader.d.ts +33 -0
- package/dist/preconditions/loader.d.ts.map +1 -0
- package/dist/preconditions/loader.js +65 -0
- package/dist/preconditions/loader.js.map +1 -0
- package/dist/preconditions/schema.d.ts +103 -0
- package/dist/preconditions/schema.d.ts.map +1 -0
- package/dist/preconditions/schema.js +93 -0
- package/dist/preconditions/schema.js.map +1 -0
- package/dist/preconditions/types.d.ts +118 -0
- package/dist/preconditions/types.d.ts.map +1 -0
- package/dist/preconditions/types.js +17 -0
- package/dist/preconditions/types.js.map +1 -0
- package/dist/queue/index.d.ts +17 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +17 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/memory-queue.d.ts +86 -0
- package/dist/queue/memory-queue.d.ts.map +1 -0
- package/dist/queue/memory-queue.js +221 -0
- package/dist/queue/memory-queue.js.map +1 -0
- package/dist/services/audit-log.d.ts +59 -0
- package/dist/services/audit-log.d.ts.map +1 -0
- package/dist/services/audit-log.js +193 -0
- package/dist/services/audit-log.js.map +1 -0
- package/dist/services/auth-error-parser.d.ts +36 -0
- package/dist/services/auth-error-parser.d.ts.map +1 -0
- package/dist/services/auth-error-parser.js +90 -0
- package/dist/services/auth-error-parser.js.map +1 -0
- package/dist/services/deployment-doctor.d.ts +109 -0
- package/dist/services/deployment-doctor.d.ts.map +1 -0
- package/dist/services/deployment-doctor.js +476 -0
- package/dist/services/deployment-doctor.js.map +1 -0
- package/dist/services/deployment-notifications.d.ts +41 -0
- package/dist/services/deployment-notifications.d.ts.map +1 -0
- package/dist/services/deployment-notifications.js +161 -0
- package/dist/services/deployment-notifications.js.map +1 -0
- package/dist/services/deployment-progress.d.ts +89 -0
- package/dist/services/deployment-progress.d.ts.map +1 -0
- package/dist/services/deployment-progress.js +244 -0
- package/dist/services/deployment-progress.js.map +1 -0
- package/dist/services/deployment-service.d.ts +97 -0
- package/dist/services/deployment-service.d.ts.map +1 -0
- package/dist/services/deployment-service.js +375 -0
- package/dist/services/deployment-service.js.map +1 -0
- package/dist/services/drift-analyzer.d.ts +86 -0
- package/dist/services/drift-analyzer.d.ts.map +1 -0
- package/dist/services/drift-analyzer.js +273 -0
- package/dist/services/drift-analyzer.js.map +1 -0
- package/dist/services/environment-setup.d.ts +97 -0
- package/dist/services/environment-setup.d.ts.map +1 -0
- package/dist/services/environment-setup.js +250 -0
- package/dist/services/environment-setup.js.map +1 -0
- package/dist/services/health-check.d.ts +168 -0
- package/dist/services/health-check.d.ts.map +1 -0
- package/dist/services/health-check.js +705 -0
- package/dist/services/health-check.js.map +1 -0
- package/dist/services/index.d.ts +39 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +39 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/logger.d.ts +139 -0
- package/dist/services/logger.d.ts.map +1 -0
- package/dist/services/logger.js +268 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/services/notification-service.d.ts +55 -0
- package/dist/services/notification-service.d.ts.map +1 -0
- package/dist/services/notification-service.js +184 -0
- package/dist/services/notification-service.js.map +1 -0
- package/dist/services/risk-analyzer.d.ts +252 -0
- package/dist/services/risk-analyzer.d.ts.map +1 -0
- package/dist/services/risk-analyzer.js +866 -0
- package/dist/services/risk-analyzer.js.map +1 -0
- package/dist/services/rollback.d.ts +57 -0
- package/dist/services/rollback.d.ts.map +1 -0
- package/dist/services/rollback.js +270 -0
- package/dist/services/rollback.js.map +1 -0
- package/dist/services/scheduler.d.ts +80 -0
- package/dist/services/scheduler.d.ts.map +1 -0
- package/dist/services/scheduler.js +350 -0
- package/dist/services/scheduler.js.map +1 -0
- package/dist/services/secrets.d.ts +31 -0
- package/dist/services/secrets.d.ts.map +1 -0
- package/dist/services/secrets.js +206 -0
- package/dist/services/secrets.js.map +1 -0
- package/dist/services/settings-service.d.ts +132 -0
- package/dist/services/settings-service.d.ts.map +1 -0
- package/dist/services/settings-service.js +378 -0
- package/dist/services/settings-service.js.map +1 -0
- package/dist/services/solution-diff.d.ts +127 -0
- package/dist/services/solution-diff.d.ts.map +1 -0
- package/dist/services/solution-diff.js +260 -0
- package/dist/services/solution-diff.js.map +1 -0
- package/dist/services/solution-mode-detector.d.ts +35 -0
- package/dist/services/solution-mode-detector.d.ts.map +1 -0
- package/dist/services/solution-mode-detector.js +84 -0
- package/dist/services/solution-mode-detector.js.map +1 -0
- package/dist/services/tenant-resolver.d.ts +55 -0
- package/dist/services/tenant-resolver.d.ts.map +1 -0
- package/dist/services/tenant-resolver.js +126 -0
- package/dist/services/tenant-resolver.js.map +1 -0
- package/dist/services/unmanaged-customizations.d.ts +104 -0
- package/dist/services/unmanaged-customizations.d.ts.map +1 -0
- package/dist/services/unmanaged-customizations.js +521 -0
- package/dist/services/unmanaged-customizations.js.map +1 -0
- package/dist/services/url-templater.d.ts +184 -0
- package/dist/services/url-templater.d.ts.map +1 -0
- package/dist/services/url-templater.js +327 -0
- package/dist/services/url-templater.js.map +1 -0
- package/dist/services/version-checker.d.ts +108 -0
- package/dist/services/version-checker.d.ts.map +1 -0
- package/dist/services/version-checker.js +403 -0
- package/dist/services/version-checker.js.map +1 -0
- package/dist/services/waves.d.ts +90 -0
- package/dist/services/waves.d.ts.map +1 -0
- package/dist/services/waves.js +222 -0
- package/dist/services/waves.js.map +1 -0
- package/dist/services/webhook.d.ts +95 -0
- package/dist/services/webhook.d.ts.map +1 -0
- package/dist/services/webhook.js +244 -0
- package/dist/services/webhook.js.map +1 -0
- package/dist/utils/deployment-tools.d.ts +110 -0
- package/dist/utils/deployment-tools.d.ts.map +1 -0
- package/dist/utils/deployment-tools.js +121 -0
- package/dist/utils/deployment-tools.js.map +1 -0
- package/dist/utils/index.d.ts +17 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2024 Pax8, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Configuration
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/** Weights for risk factors (higher = more impact on score) */
|
|
20
|
+
const WEIGHTS = {
|
|
21
|
+
versionsBehind: 8,
|
|
22
|
+
lastDeployResult: 7,
|
|
23
|
+
timeSinceLastDeploy: 5,
|
|
24
|
+
deploySuccessRate: 4,
|
|
25
|
+
productionTag: 6,
|
|
26
|
+
};
|
|
27
|
+
const HIGH_RISK_TAGS = ["production", "enterprise", "priority", "finance"];
|
|
28
|
+
const LOW_RISK_TAGS = ["test", "staging", "dev", "sandbox"];
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// DriftAnalyzer
|
|
31
|
+
// ============================================================================
|
|
32
|
+
export class DriftAnalyzer {
|
|
33
|
+
/**
|
|
34
|
+
* Analyze drift risk for a single tenant
|
|
35
|
+
*/
|
|
36
|
+
analyzeTenant(tenant, versionStatus, history) {
|
|
37
|
+
const factors = [];
|
|
38
|
+
const outdatedSolutions = versionStatus.solutions.filter((s) => s.status === "outdated");
|
|
39
|
+
// If tenant is current, short-circuit
|
|
40
|
+
if (versionStatus.overallStatus === "current") {
|
|
41
|
+
return {
|
|
42
|
+
tenantId: tenant.tenantId,
|
|
43
|
+
tenantName: tenant.name,
|
|
44
|
+
environmentUrl: tenant.environmentUrl,
|
|
45
|
+
riskLevel: "low",
|
|
46
|
+
riskScore: 0,
|
|
47
|
+
recommendation: "current",
|
|
48
|
+
recommendationReason: "All solutions are at the expected version",
|
|
49
|
+
factors: [],
|
|
50
|
+
versionStatus,
|
|
51
|
+
outdatedSolutions: [],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Factor 1: How many versions behind
|
|
55
|
+
const maxDrift = Math.max(...outdatedSolutions.map((s) => Math.abs(s.versionDrift)), 0);
|
|
56
|
+
if (maxDrift >= 3) {
|
|
57
|
+
factors.push({
|
|
58
|
+
name: "versions_behind",
|
|
59
|
+
level: "high",
|
|
60
|
+
weight: WEIGHTS.versionsBehind,
|
|
61
|
+
description: `${maxDrift} version(s) behind — significant gap increases upgrade risk`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else if (maxDrift === 2) {
|
|
65
|
+
factors.push({
|
|
66
|
+
name: "versions_behind",
|
|
67
|
+
level: "medium",
|
|
68
|
+
weight: WEIGHTS.versionsBehind,
|
|
69
|
+
description: `${maxDrift} version(s) behind`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else if (maxDrift === 1) {
|
|
73
|
+
factors.push({
|
|
74
|
+
name: "versions_behind",
|
|
75
|
+
level: "low",
|
|
76
|
+
weight: WEIGHTS.versionsBehind,
|
|
77
|
+
description: "1 version behind — minor update",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// Factor 2: Last deployment result
|
|
81
|
+
if (history) {
|
|
82
|
+
if (history.lastDeployResult === "failure") {
|
|
83
|
+
factors.push({
|
|
84
|
+
name: "last_deploy_failed",
|
|
85
|
+
level: "high",
|
|
86
|
+
weight: WEIGHTS.lastDeployResult,
|
|
87
|
+
description: "Last deployment failed — retrying may hit the same issue",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
else if (history.lastDeployResult === "success") {
|
|
91
|
+
factors.push({
|
|
92
|
+
name: "last_deploy_succeeded",
|
|
93
|
+
level: "low",
|
|
94
|
+
weight: WEIGHTS.lastDeployResult,
|
|
95
|
+
description: "Last deployment succeeded",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// Factor 3: Time since last deploy
|
|
99
|
+
if (history.lastDeployDate) {
|
|
100
|
+
const daysSince = Math.floor((Date.now() - new Date(history.lastDeployDate).getTime()) / (1000 * 60 * 60 * 24));
|
|
101
|
+
if (daysSince > 90) {
|
|
102
|
+
factors.push({
|
|
103
|
+
name: "stale_environment",
|
|
104
|
+
level: "high",
|
|
105
|
+
weight: WEIGHTS.timeSinceLastDeploy,
|
|
106
|
+
description: `${daysSince} days since last deploy — environment may have drifted significantly`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else if (daysSince > 30) {
|
|
110
|
+
factors.push({
|
|
111
|
+
name: "aging_environment",
|
|
112
|
+
level: "medium",
|
|
113
|
+
weight: WEIGHTS.timeSinceLastDeploy,
|
|
114
|
+
description: `${daysSince} days since last deploy`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
factors.push({
|
|
119
|
+
name: "recent_deploy",
|
|
120
|
+
level: "low",
|
|
121
|
+
weight: WEIGHTS.timeSinceLastDeploy,
|
|
122
|
+
description: `${daysSince} days since last deploy — recently active`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Factor 4: Deploy success rate
|
|
127
|
+
if (history.totalDeploys > 0) {
|
|
128
|
+
const successRate = history.successfulDeploys / history.totalDeploys;
|
|
129
|
+
if (successRate < 0.5) {
|
|
130
|
+
factors.push({
|
|
131
|
+
name: "low_success_rate",
|
|
132
|
+
level: "high",
|
|
133
|
+
weight: WEIGHTS.deploySuccessRate,
|
|
134
|
+
description: `${Math.round(successRate * 100)}% deploy success rate — this tenant is flaky`,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
else if (successRate < 0.8) {
|
|
138
|
+
factors.push({
|
|
139
|
+
name: "moderate_success_rate",
|
|
140
|
+
level: "medium",
|
|
141
|
+
weight: WEIGHTS.deploySuccessRate,
|
|
142
|
+
description: `${Math.round(successRate * 100)}% deploy success rate`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Factor 5: Tenant tags (production = higher risk)
|
|
148
|
+
const tags = tenant.tags || [];
|
|
149
|
+
const hasHighRiskTag = tags.some((t) => HIGH_RISK_TAGS.includes(t.toLowerCase()));
|
|
150
|
+
const hasLowRiskTag = tags.some((t) => LOW_RISK_TAGS.includes(t.toLowerCase()));
|
|
151
|
+
if (hasHighRiskTag) {
|
|
152
|
+
factors.push({
|
|
153
|
+
name: "production_tenant",
|
|
154
|
+
level: "medium",
|
|
155
|
+
weight: WEIGHTS.productionTag,
|
|
156
|
+
description: `Tagged as ${tags.filter((t) => HIGH_RISK_TAGS.includes(t.toLowerCase())).join(", ")} — higher blast radius`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
else if (hasLowRiskTag) {
|
|
160
|
+
factors.push({
|
|
161
|
+
name: "non_production_tenant",
|
|
162
|
+
level: "low",
|
|
163
|
+
weight: WEIGHTS.productionTag,
|
|
164
|
+
description: `Tagged as ${tags.filter((t) => LOW_RISK_TAGS.includes(t.toLowerCase())).join(", ")} — lower risk`,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Calculate composite score
|
|
168
|
+
const riskScore = this.calculateScore(factors);
|
|
169
|
+
const riskLevel = this.scoreToLevel(riskScore);
|
|
170
|
+
const { recommendation, reason } = this.getRecommendation(riskLevel, factors);
|
|
171
|
+
return {
|
|
172
|
+
tenantId: tenant.tenantId,
|
|
173
|
+
tenantName: tenant.name,
|
|
174
|
+
environmentUrl: tenant.environmentUrl,
|
|
175
|
+
riskLevel,
|
|
176
|
+
riskScore,
|
|
177
|
+
recommendation,
|
|
178
|
+
recommendationReason: reason,
|
|
179
|
+
factors,
|
|
180
|
+
versionStatus,
|
|
181
|
+
outdatedSolutions,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Analyze drift risk for a fleet of tenants
|
|
186
|
+
*/
|
|
187
|
+
analyzeFleet(tenants, versionStatuses, histories) {
|
|
188
|
+
const analyses = tenants.map((tenant, i) => {
|
|
189
|
+
const versionStatus = versionStatuses[i];
|
|
190
|
+
const history = histories?.get(tenant.tenantId);
|
|
191
|
+
return this.analyzeTenant(tenant, versionStatus, history);
|
|
192
|
+
});
|
|
193
|
+
return {
|
|
194
|
+
tenants: analyses,
|
|
195
|
+
summary: {
|
|
196
|
+
total: analyses.length,
|
|
197
|
+
current: analyses.filter((a) => a.recommendation === "current").length,
|
|
198
|
+
safeToUpdate: analyses.filter((a) => a.recommendation === "safe_to_update").length,
|
|
199
|
+
reviewRecommended: analyses.filter((a) => a.recommendation === "review_recommended").length,
|
|
200
|
+
risky: analyses.filter((a) => a.recommendation === "update_risky").length,
|
|
201
|
+
doNotUpdate: analyses.filter((a) => a.recommendation === "do_not_update").length,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
// ============================================================================
|
|
206
|
+
// Private
|
|
207
|
+
// ============================================================================
|
|
208
|
+
calculateScore(factors) {
|
|
209
|
+
if (factors.length === 0)
|
|
210
|
+
return 0;
|
|
211
|
+
let weightedSum = 0;
|
|
212
|
+
let totalWeight = 0;
|
|
213
|
+
for (const factor of factors) {
|
|
214
|
+
const levelScore = factor.level === "high" ? 100 : factor.level === "medium" ? 50 : 10;
|
|
215
|
+
weightedSum += levelScore * factor.weight;
|
|
216
|
+
totalWeight += factor.weight;
|
|
217
|
+
}
|
|
218
|
+
return totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
|
|
219
|
+
}
|
|
220
|
+
scoreToLevel(score) {
|
|
221
|
+
if (score >= 65)
|
|
222
|
+
return "high";
|
|
223
|
+
if (score >= 35)
|
|
224
|
+
return "medium";
|
|
225
|
+
return "low";
|
|
226
|
+
}
|
|
227
|
+
getRecommendation(level, factors) {
|
|
228
|
+
const hasLastDeployFailed = factors.some((f) => f.name === "last_deploy_failed");
|
|
229
|
+
const hasStaleEnv = factors.some((f) => f.name === "stale_environment");
|
|
230
|
+
const hasLowSuccessRate = factors.some((f) => f.name === "low_success_rate");
|
|
231
|
+
// Hard blockers
|
|
232
|
+
if (hasLastDeployFailed && hasStaleEnv) {
|
|
233
|
+
return {
|
|
234
|
+
recommendation: "do_not_update",
|
|
235
|
+
reason: "Last deploy failed and environment is stale — investigate before retrying",
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (hasLowSuccessRate && hasLastDeployFailed) {
|
|
239
|
+
return {
|
|
240
|
+
recommendation: "do_not_update",
|
|
241
|
+
reason: "Chronically failing tenant — fix underlying issues first",
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// Score-based
|
|
245
|
+
if (level === "high") {
|
|
246
|
+
return {
|
|
247
|
+
recommendation: "update_risky",
|
|
248
|
+
reason: this.getTopRiskDescription(factors),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
if (level === "medium") {
|
|
252
|
+
return {
|
|
253
|
+
recommendation: "review_recommended",
|
|
254
|
+
reason: this.getTopRiskDescription(factors),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
recommendation: "safe_to_update",
|
|
259
|
+
reason: "Low risk — safe to proceed",
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
getTopRiskDescription(factors) {
|
|
263
|
+
const highFactors = factors.filter((f) => f.level === "high" || f.level === "medium");
|
|
264
|
+
if (highFactors.length === 0)
|
|
265
|
+
return "Minor risk factors present";
|
|
266
|
+
// Sort by weight descending, take top factor
|
|
267
|
+
highFactors.sort((a, b) => b.weight - a.weight);
|
|
268
|
+
return highFactors[0].description;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Export singleton
|
|
272
|
+
export const driftAnalyzer = new DriftAnalyzer();
|
|
273
|
+
//# sourceMappingURL=drift-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift-analyzer.js","sourceRoot":"","sources":["../../src/services/drift-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2024 Pax8, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Environment Setup Service
|
|
18
|
+
*
|
|
19
|
+
* Manages Power Platform application user lifecycle:
|
|
20
|
+
* - Checking if an app user exists in a Dataverse environment
|
|
21
|
+
* - Verifying security role assignments
|
|
22
|
+
* - Creating app users and assigning roles
|
|
23
|
+
* - Validating tenant readiness for deployment
|
|
24
|
+
*
|
|
25
|
+
* Extracted from CLI setup.ts, validate.ts, and deploy.ts (prepareEnvironment)
|
|
26
|
+
* to eliminate duplication and make the logic testable and reusable.
|
|
27
|
+
*/
|
|
28
|
+
import { DataverseClient } from "../dataverse/client.js";
|
|
29
|
+
export interface SystemUser {
|
|
30
|
+
systemuserid: string;
|
|
31
|
+
fullname?: string;
|
|
32
|
+
applicationid?: string;
|
|
33
|
+
isdisabled?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export type SetupStatusCode = "ready" | "needs_setup" | "partial" | "error";
|
|
36
|
+
export interface SetupStatus {
|
|
37
|
+
tenantName: string;
|
|
38
|
+
environmentUrl: string;
|
|
39
|
+
appRegistered: boolean;
|
|
40
|
+
roleAssigned: boolean;
|
|
41
|
+
status: SetupStatusCode;
|
|
42
|
+
error?: string;
|
|
43
|
+
userId?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface TenantValidationResult {
|
|
46
|
+
appUserExists: boolean;
|
|
47
|
+
hasSystemAdminRole: boolean;
|
|
48
|
+
userId?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface PrepareEnvironmentResult {
|
|
51
|
+
success: boolean;
|
|
52
|
+
message: string;
|
|
53
|
+
}
|
|
54
|
+
export declare class EnvironmentSetupService {
|
|
55
|
+
/**
|
|
56
|
+
* Check if an app user exists and has the System Administrator role.
|
|
57
|
+
*
|
|
58
|
+
* This is the core validation used by `pax8-cta validate` and `pax8-cta setup --check`.
|
|
59
|
+
*/
|
|
60
|
+
validateTenant(client: DataverseClient, appId: string): Promise<TenantValidationResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Check the full setup status for a tenant, including error handling.
|
|
63
|
+
*
|
|
64
|
+
* Returns a structured status object suitable for display in tables or JSON output.
|
|
65
|
+
* Used by `pax8-cta setup --check`.
|
|
66
|
+
*/
|
|
67
|
+
checkSetupStatus(client: DataverseClient, appId: string, tenantName: string, environmentUrl: string): Promise<SetupStatus>;
|
|
68
|
+
/**
|
|
69
|
+
* Create an application user in the Dataverse environment.
|
|
70
|
+
*
|
|
71
|
+
* Finds the root business unit and creates the app user bound to it.
|
|
72
|
+
* Returns the new user's system user ID.
|
|
73
|
+
*/
|
|
74
|
+
createAppUser(client: DataverseClient, appId: string): Promise<string>;
|
|
75
|
+
/**
|
|
76
|
+
* Assign the System Administrator role to a user.
|
|
77
|
+
*/
|
|
78
|
+
assignSystemAdminRole(client: DataverseClient, userId: string, environmentUrl: string): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Ensure an app user is created and has System Administrator role.
|
|
81
|
+
*
|
|
82
|
+
* This is the "setup" action used by both `pax8-cta setup` and
|
|
83
|
+
* the auto-setup step in `pax8-cta deploy`.
|
|
84
|
+
*/
|
|
85
|
+
setupTenant(client: DataverseClient, appId: string, environmentUrl: string, currentStatus: SetupStatus): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Prepare an environment for deployment by ensuring app user exists with proper permissions.
|
|
88
|
+
*
|
|
89
|
+
* Combines check + setup into a single operation. Returns a result suitable for
|
|
90
|
+
* progress reporting.
|
|
91
|
+
*
|
|
92
|
+
* This was previously `prepareEnvironment()` in deploy.ts.
|
|
93
|
+
*/
|
|
94
|
+
prepareEnvironment(client: DataverseClient, appId: string, environmentUrl: string): Promise<PrepareEnvironmentResult>;
|
|
95
|
+
}
|
|
96
|
+
export declare const environmentSetupService: EnvironmentSetupService;
|
|
97
|
+
//# sourceMappingURL=environment-setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-setup.d.ts","sourceRoot":"","sources":["../../src/services/environment-setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAOzD,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5E,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,qBAAa,uBAAuB;IAClC;;;;OAIG;IACG,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiC7F;;;;;OAKG;IACG,gBAAgB,CACpB,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,CAAC;IA2DvB;;;;;OAKG;IACG,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgC5E;;OAEG;IACG,qBAAqB,CACzB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC;IAoBhB;;;;;OAKG;IACG,WAAW,CACf,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,WAAW,GACzB,OAAO,CAAC,IAAI,CAAC;IAchB;;;;;;;OAOG;IACG,kBAAkB,CACtB,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,wBAAwB,CAAC;CAmErC;AAGD,eAAO,MAAM,uBAAuB,yBAAgC,CAAC"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2024 Pax8, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Service
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export class EnvironmentSetupService {
|
|
20
|
+
/**
|
|
21
|
+
* Check if an app user exists and has the System Administrator role.
|
|
22
|
+
*
|
|
23
|
+
* This is the core validation used by `pax8-cta validate` and `pax8-cta setup --check`.
|
|
24
|
+
*/
|
|
25
|
+
async validateTenant(client, appId) {
|
|
26
|
+
// Check if app user exists
|
|
27
|
+
const result = await client.get("/systemusers", {
|
|
28
|
+
$filter: `applicationid eq '${appId}'`,
|
|
29
|
+
$select: "systemuserid,fullname,applicationid,isdisabled",
|
|
30
|
+
});
|
|
31
|
+
if (result.value.length === 0) {
|
|
32
|
+
return {
|
|
33
|
+
appUserExists: false,
|
|
34
|
+
hasSystemAdminRole: false,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const user = result.value[0];
|
|
38
|
+
// Check if System Administrator role is assigned
|
|
39
|
+
const rolesResult = await client.get(`/systemusers(${user.systemuserid})/systemuserroles_association`, {
|
|
40
|
+
$select: "roleid,name",
|
|
41
|
+
});
|
|
42
|
+
const hasAdminRole = rolesResult.value.some((r) => r.name === "System Administrator");
|
|
43
|
+
return {
|
|
44
|
+
appUserExists: true,
|
|
45
|
+
hasSystemAdminRole: hasAdminRole,
|
|
46
|
+
userId: user.systemuserid,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check the full setup status for a tenant, including error handling.
|
|
51
|
+
*
|
|
52
|
+
* Returns a structured status object suitable for display in tables or JSON output.
|
|
53
|
+
* Used by `pax8-cta setup --check`.
|
|
54
|
+
*/
|
|
55
|
+
async checkSetupStatus(client, appId, tenantName, environmentUrl) {
|
|
56
|
+
try {
|
|
57
|
+
const validation = await this.validateTenant(client, appId);
|
|
58
|
+
if (!validation.appUserExists) {
|
|
59
|
+
return {
|
|
60
|
+
tenantName,
|
|
61
|
+
environmentUrl,
|
|
62
|
+
appRegistered: false,
|
|
63
|
+
roleAssigned: false,
|
|
64
|
+
status: "needs_setup",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (!validation.hasSystemAdminRole) {
|
|
68
|
+
return {
|
|
69
|
+
tenantName,
|
|
70
|
+
environmentUrl,
|
|
71
|
+
appRegistered: true,
|
|
72
|
+
roleAssigned: false,
|
|
73
|
+
status: "partial",
|
|
74
|
+
userId: validation.userId,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
tenantName,
|
|
79
|
+
environmentUrl,
|
|
80
|
+
appRegistered: true,
|
|
81
|
+
roleAssigned: true,
|
|
82
|
+
status: "ready",
|
|
83
|
+
userId: validation.userId,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
88
|
+
// Check if it's an auth error (app not registered at tenant level)
|
|
89
|
+
if (errorMsg.includes("not a member of the organization")) {
|
|
90
|
+
return {
|
|
91
|
+
tenantName,
|
|
92
|
+
environmentUrl,
|
|
93
|
+
appRegistered: false,
|
|
94
|
+
roleAssigned: false,
|
|
95
|
+
status: "needs_setup",
|
|
96
|
+
error: "App not registered in this environment (bootstrap required)",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
tenantName,
|
|
101
|
+
environmentUrl,
|
|
102
|
+
appRegistered: false,
|
|
103
|
+
roleAssigned: false,
|
|
104
|
+
status: "error",
|
|
105
|
+
error: errorMsg,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create an application user in the Dataverse environment.
|
|
111
|
+
*
|
|
112
|
+
* Finds the root business unit and creates the app user bound to it.
|
|
113
|
+
* Returns the new user's system user ID.
|
|
114
|
+
*/
|
|
115
|
+
async createAppUser(client, appId) {
|
|
116
|
+
// Get root business unit
|
|
117
|
+
const buResult = await client.get("/businessunits", {
|
|
118
|
+
$filter: "parentbusinessunitid eq null",
|
|
119
|
+
$select: "businessunitid,name",
|
|
120
|
+
});
|
|
121
|
+
if (buResult.value.length === 0) {
|
|
122
|
+
throw new Error("Could not find root business unit");
|
|
123
|
+
}
|
|
124
|
+
const buId = buResult.value[0].businessunitid;
|
|
125
|
+
// Create app user
|
|
126
|
+
await client.post("/systemusers", {
|
|
127
|
+
applicationid: appId,
|
|
128
|
+
"businessunitid@odata.bind": `/businessunits(${buId})`,
|
|
129
|
+
});
|
|
130
|
+
// Get the newly created user's ID
|
|
131
|
+
const userResult = await client.get("/systemusers", {
|
|
132
|
+
$filter: `applicationid eq '${appId}'`,
|
|
133
|
+
$select: "systemuserid",
|
|
134
|
+
});
|
|
135
|
+
if (userResult.value.length === 0) {
|
|
136
|
+
throw new Error("Failed to create app user");
|
|
137
|
+
}
|
|
138
|
+
return userResult.value[0].systemuserid;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Assign the System Administrator role to a user.
|
|
142
|
+
*/
|
|
143
|
+
async assignSystemAdminRole(client, userId, environmentUrl) {
|
|
144
|
+
// Get System Administrator role
|
|
145
|
+
const roleResult = await client.get("/roles", {
|
|
146
|
+
$filter: "name eq 'System Administrator'",
|
|
147
|
+
$select: "roleid,name",
|
|
148
|
+
});
|
|
149
|
+
if (roleResult.value.length === 0) {
|
|
150
|
+
throw new Error("Could not find System Administrator role");
|
|
151
|
+
}
|
|
152
|
+
const roleId = roleResult.value[0].roleid;
|
|
153
|
+
// Assign role to user
|
|
154
|
+
const apiUrl = environmentUrl.replace(/\/$/, "") + "/api/data/v9.2";
|
|
155
|
+
await client.post(`/systemusers(${userId})/systemuserroles_association/$ref`, {
|
|
156
|
+
"@odata.id": `${apiUrl}/roles(${roleId})`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Ensure an app user is created and has System Administrator role.
|
|
161
|
+
*
|
|
162
|
+
* This is the "setup" action used by both `pax8-cta setup` and
|
|
163
|
+
* the auto-setup step in `pax8-cta deploy`.
|
|
164
|
+
*/
|
|
165
|
+
async setupTenant(client, appId, environmentUrl, currentStatus) {
|
|
166
|
+
let userId = currentStatus.userId;
|
|
167
|
+
// Create app user if needed
|
|
168
|
+
if (!currentStatus.appRegistered) {
|
|
169
|
+
userId = await this.createAppUser(client, appId);
|
|
170
|
+
}
|
|
171
|
+
// Assign System Administrator role if needed
|
|
172
|
+
if (!currentStatus.roleAssigned && userId) {
|
|
173
|
+
await this.assignSystemAdminRole(client, userId, environmentUrl);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Prepare an environment for deployment by ensuring app user exists with proper permissions.
|
|
178
|
+
*
|
|
179
|
+
* Combines check + setup into a single operation. Returns a result suitable for
|
|
180
|
+
* progress reporting.
|
|
181
|
+
*
|
|
182
|
+
* This was previously `prepareEnvironment()` in deploy.ts.
|
|
183
|
+
*/
|
|
184
|
+
async prepareEnvironment(client, appId, environmentUrl) {
|
|
185
|
+
try {
|
|
186
|
+
const validation = await this.validateTenant(client, appId);
|
|
187
|
+
if (validation.appUserExists && validation.hasSystemAdminRole) {
|
|
188
|
+
return { success: true, message: "Ready" };
|
|
189
|
+
}
|
|
190
|
+
// Need to create user or assign role
|
|
191
|
+
if (!validation.appUserExists) {
|
|
192
|
+
try {
|
|
193
|
+
const userId = await this.createAppUser(client, appId);
|
|
194
|
+
await this.assignSystemAdminRole(client, userId, environmentUrl);
|
|
195
|
+
return {
|
|
196
|
+
success: true,
|
|
197
|
+
message: "Created app user and assigned System Administrator role",
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
202
|
+
if (errorMsg.includes("not a member of the organization")) {
|
|
203
|
+
return {
|
|
204
|
+
success: false,
|
|
205
|
+
message: "App not registered (requires manual bootstrap in Power Platform admin center)",
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
success: false,
|
|
210
|
+
message: `Failed to create app user: ${errorMsg}`,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// User exists but needs role
|
|
215
|
+
if (validation.userId) {
|
|
216
|
+
try {
|
|
217
|
+
await this.assignSystemAdminRole(client, validation.userId, environmentUrl);
|
|
218
|
+
return {
|
|
219
|
+
success: true,
|
|
220
|
+
message: "Assigned System Administrator role",
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
225
|
+
return {
|
|
226
|
+
success: false,
|
|
227
|
+
message: `Failed to assign role: ${errorMsg}`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return { success: false, message: "Unexpected state" };
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
235
|
+
if (errorMsg.includes("not a member of the organization")) {
|
|
236
|
+
return {
|
|
237
|
+
success: false,
|
|
238
|
+
message: "App not registered (requires manual bootstrap in Power Platform admin center)",
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
success: false,
|
|
243
|
+
message: `Error: ${errorMsg}`,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Export singleton for convenience
|
|
249
|
+
export const environmentSetupService = new EnvironmentSetupService();
|
|
250
|
+
//# sourceMappingURL=environment-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment-setup.js","sourceRoot":"","sources":["../../src/services/environment-setup.ts"],"names":[],"mappings":"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"}
|