@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,375 @@
|
|
|
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
|
+
import { TokenManager } from "../auth/token-manager.js";
|
|
17
|
+
import { DataverseClient } from "../dataverse/client.js";
|
|
18
|
+
import { SolutionOperations } from "../dataverse/solution-ops.js";
|
|
19
|
+
import { ConnectionOperations } from "../dataverse/connection-refs.js";
|
|
20
|
+
import { PowerPlatformAdminClient } from "../powerplatform/admin-client.js";
|
|
21
|
+
import { DEFAULT_DEPLOYMENT_CONCURRENCY } from "../constants.js";
|
|
22
|
+
import { GdapError, ErrorCode } from "../errors.js";
|
|
23
|
+
/**
|
|
24
|
+
* Service for deploying solutions to customer tenants via GDAP
|
|
25
|
+
*/
|
|
26
|
+
export class DeploymentService {
|
|
27
|
+
config;
|
|
28
|
+
tokenManagers = new Map();
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this.config = config;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get or create a cached TokenManager for a tenant.
|
|
34
|
+
* Avoids creating redundant TokenManager instances for the same tenant.
|
|
35
|
+
*/
|
|
36
|
+
getTokenManager(tenantId) {
|
|
37
|
+
let manager = this.tokenManagers.get(tenantId);
|
|
38
|
+
if (!manager) {
|
|
39
|
+
manager = new TokenManager({
|
|
40
|
+
tenantId,
|
|
41
|
+
clientId: this.config.clientId,
|
|
42
|
+
clientSecret: this.config.clientSecret,
|
|
43
|
+
});
|
|
44
|
+
this.tokenManagers.set(tenantId, manager);
|
|
45
|
+
}
|
|
46
|
+
return manager;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Deploy a solution to a single tenant
|
|
50
|
+
*/
|
|
51
|
+
async deployToTenant(solutionBase64, target, onProgress) {
|
|
52
|
+
const startedAt = new Date().toISOString();
|
|
53
|
+
const startTime = Date.now();
|
|
54
|
+
const emitProgress = (step, progress, status = "in_progress") => {
|
|
55
|
+
onProgress?.({
|
|
56
|
+
tenantId: target.tenantId,
|
|
57
|
+
tenantName: target.tenantName,
|
|
58
|
+
status,
|
|
59
|
+
step,
|
|
60
|
+
progress,
|
|
61
|
+
startedAt,
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
try {
|
|
65
|
+
// Step 1: Authenticate to customer tenant
|
|
66
|
+
emitProgress("authenticating", 5);
|
|
67
|
+
const customerTokenManager = this.getTokenManager(target.tenantId);
|
|
68
|
+
// Verify we can get a token
|
|
69
|
+
await customerTokenManager.getDataverseToken(target.environmentUrl);
|
|
70
|
+
emitProgress("authenticating", 15);
|
|
71
|
+
// Step 2: Validate environment
|
|
72
|
+
emitProgress("validating", 20);
|
|
73
|
+
const dataverseClient = new DataverseClient({
|
|
74
|
+
environmentUrl: target.environmentUrl,
|
|
75
|
+
tokenManager: customerTokenManager,
|
|
76
|
+
clientId: this.config.clientId,
|
|
77
|
+
});
|
|
78
|
+
// Quick health check - try to query solutions
|
|
79
|
+
try {
|
|
80
|
+
await dataverseClient.querySolutions();
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// Check if this is an app user setup issue
|
|
84
|
+
const isAppUserError = this.isAppUserNotRegisteredError(error);
|
|
85
|
+
if (isAppUserError) {
|
|
86
|
+
// Check if auto-setup is enabled (default: true)
|
|
87
|
+
const autoSetup = target.autoSetup !== false;
|
|
88
|
+
if (!autoSetup) {
|
|
89
|
+
// Auto-setup is disabled, provide helpful error message
|
|
90
|
+
throw new GdapError(ErrorCode.GDAP_APP_USER_NOT_REGISTERED, `Application user not registered in environment.\n\n` +
|
|
91
|
+
`Auto-setup is disabled (autoSetup: false in config).\n\n` +
|
|
92
|
+
`To fix manually:\n` +
|
|
93
|
+
`1. Go to https://admin.powerplatform.microsoft.com\n` +
|
|
94
|
+
`2. Select the environment → Settings → Users + permissions → Application users\n` +
|
|
95
|
+
`3. Click "+ New app user" and add your application (Client ID: ${this.config.clientId})\n` +
|
|
96
|
+
`4. Assign the "System Administrator" security role\n` +
|
|
97
|
+
`5. Save and retry the deployment\n\n` +
|
|
98
|
+
`Or enable auto-setup by removing 'autoSetup: false' from your tenant configuration.`, {
|
|
99
|
+
clientId: this.config.clientId,
|
|
100
|
+
tenantId: target.tenantId,
|
|
101
|
+
tenantName: target.tenantName,
|
|
102
|
+
environmentUrl: target.environmentUrl,
|
|
103
|
+
}, { cause: error });
|
|
104
|
+
}
|
|
105
|
+
// Auto-setup the application user
|
|
106
|
+
console.log(`Application user not registered. Auto-setting up for ${target.tenantName}...`);
|
|
107
|
+
await this.setupApplicationUser(target, customerTokenManager);
|
|
108
|
+
// Retry the query
|
|
109
|
+
await dataverseClient.querySolutions();
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Re-throw other errors
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
emitProgress("validating", 30);
|
|
117
|
+
// Step 3: Import solution
|
|
118
|
+
emitProgress("uploading", 35);
|
|
119
|
+
const solutionOps = new SolutionOperations(dataverseClient);
|
|
120
|
+
// Import solution from base64
|
|
121
|
+
emitProgress("importing", 40);
|
|
122
|
+
const importResult = await this.importSolutionFromBase64(solutionOps, solutionBase64, (importProgress) => {
|
|
123
|
+
// Map import progress (0-100) to our step range (40-70)
|
|
124
|
+
const mappedProgress = 40 + Math.floor(importProgress * 0.3);
|
|
125
|
+
emitProgress("importing", mappedProgress);
|
|
126
|
+
});
|
|
127
|
+
if (!importResult.success) {
|
|
128
|
+
throw new Error(importResult.error || "Solution import failed");
|
|
129
|
+
}
|
|
130
|
+
emitProgress("importing", 70);
|
|
131
|
+
// Step 4: Configure connections (if provided)
|
|
132
|
+
if (target.connectionMappings && target.connectionMappings.length > 0) {
|
|
133
|
+
emitProgress("configuring_connections", 75);
|
|
134
|
+
const connectionOps = new ConnectionOperations(dataverseClient);
|
|
135
|
+
const connResult = await connectionOps.applyConnectionMappings(target.connectionMappings);
|
|
136
|
+
if (!connResult.success) {
|
|
137
|
+
console.warn("Connection mapping warnings:", connResult.errors);
|
|
138
|
+
// Don't fail the deployment for connection mapping issues
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
emitProgress("configuring_connections", 80);
|
|
142
|
+
// Step 5: Configure environment variables (if provided)
|
|
143
|
+
if (target.environmentVariables && target.environmentVariables.length > 0) {
|
|
144
|
+
emitProgress("configuring_variables", 85);
|
|
145
|
+
const connectionOps = new ConnectionOperations(dataverseClient);
|
|
146
|
+
const varResult = await connectionOps.applyEnvironmentVariables(target.environmentVariables);
|
|
147
|
+
if (!varResult.success) {
|
|
148
|
+
console.warn("Environment variable warnings:", varResult.errors);
|
|
149
|
+
// Don't fail the deployment for env var issues
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
emitProgress("configuring_variables", 90);
|
|
153
|
+
// Step 6: Verify deployment
|
|
154
|
+
emitProgress("verifying", 95);
|
|
155
|
+
// Could add additional verification here (e.g., check solution is active)
|
|
156
|
+
// Step 7: Complete
|
|
157
|
+
emitProgress("completing", 100, "completed");
|
|
158
|
+
const completedAt = new Date().toISOString();
|
|
159
|
+
return {
|
|
160
|
+
tenantId: target.tenantId,
|
|
161
|
+
tenantName: target.tenantName,
|
|
162
|
+
success: true,
|
|
163
|
+
importJobId: importResult.importJobId,
|
|
164
|
+
startedAt,
|
|
165
|
+
completedAt,
|
|
166
|
+
durationMs: Date.now() - startTime,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
const completedAt = new Date().toISOString();
|
|
171
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
172
|
+
onProgress?.({
|
|
173
|
+
tenantId: target.tenantId,
|
|
174
|
+
tenantName: target.tenantName,
|
|
175
|
+
status: "failed",
|
|
176
|
+
step: "importing", // Best guess at where it failed
|
|
177
|
+
progress: 0,
|
|
178
|
+
startedAt,
|
|
179
|
+
completedAt,
|
|
180
|
+
error: errorMessage,
|
|
181
|
+
});
|
|
182
|
+
return {
|
|
183
|
+
tenantId: target.tenantId,
|
|
184
|
+
tenantName: target.tenantName,
|
|
185
|
+
success: false,
|
|
186
|
+
error: errorMessage,
|
|
187
|
+
startedAt,
|
|
188
|
+
completedAt,
|
|
189
|
+
durationMs: Date.now() - startTime,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Deploy to multiple tenants with concurrency control
|
|
195
|
+
*/
|
|
196
|
+
async deployToTenants(solutionBase64, targets, options) {
|
|
197
|
+
const { maxConcurrent = DEFAULT_DEPLOYMENT_CONCURRENCY, onProgress } = options || {};
|
|
198
|
+
const results = [];
|
|
199
|
+
const pending = [...targets];
|
|
200
|
+
const active = [];
|
|
201
|
+
while (pending.length > 0 || active.length > 0) {
|
|
202
|
+
// Start new deployments up to max concurrency
|
|
203
|
+
while (pending.length > 0 && active.length < maxConcurrent) {
|
|
204
|
+
const target = pending.shift();
|
|
205
|
+
const promise = this.deployToTenant(solutionBase64, target, onProgress)
|
|
206
|
+
.then((result) => {
|
|
207
|
+
results.push(result);
|
|
208
|
+
})
|
|
209
|
+
.finally(() => {
|
|
210
|
+
const index = active.indexOf(promise);
|
|
211
|
+
if (index > -1)
|
|
212
|
+
active.splice(index, 1);
|
|
213
|
+
});
|
|
214
|
+
active.push(promise);
|
|
215
|
+
}
|
|
216
|
+
// Wait for at least one to complete
|
|
217
|
+
if (active.length > 0) {
|
|
218
|
+
await Promise.race(active);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return results;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Import a solution from base64 encoded content
|
|
225
|
+
*/
|
|
226
|
+
async importSolutionFromBase64(solutionOps, base64Content, onProgress) {
|
|
227
|
+
// Write to temp file (required by current SolutionOperations API)
|
|
228
|
+
const fs = await import("node:fs/promises");
|
|
229
|
+
const path = await import("node:path");
|
|
230
|
+
const os = await import("node:os");
|
|
231
|
+
const tempDir = os.tmpdir();
|
|
232
|
+
const tempFile = path.join(tempDir, `solution-${Date.now()}.zip`);
|
|
233
|
+
try {
|
|
234
|
+
// Decode and write solution
|
|
235
|
+
const buffer = Buffer.from(base64Content, "base64");
|
|
236
|
+
await fs.writeFile(tempFile, buffer);
|
|
237
|
+
// Import with progress polling
|
|
238
|
+
const importJobId = await solutionOps.importSolutionAsync(tempFile);
|
|
239
|
+
// Poll for completion
|
|
240
|
+
const result = await solutionOps.waitForImport(importJobId, {
|
|
241
|
+
pollIntervalMs: 3000,
|
|
242
|
+
timeoutMs: 600000, // 10 minutes
|
|
243
|
+
onProgress,
|
|
244
|
+
});
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
finally {
|
|
248
|
+
// Clean up temp file
|
|
249
|
+
try {
|
|
250
|
+
await fs.unlink(tempFile);
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// Ignore cleanup errors
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Validate that a tenant is ready for deployment
|
|
259
|
+
*/
|
|
260
|
+
async validateTenant(target) {
|
|
261
|
+
const errors = [];
|
|
262
|
+
const warnings = [];
|
|
263
|
+
try {
|
|
264
|
+
// Check authentication
|
|
265
|
+
const customerTokenManager = this.getTokenManager(target.tenantId);
|
|
266
|
+
try {
|
|
267
|
+
await customerTokenManager.getDataverseToken(target.environmentUrl);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
errors.push(`Authentication failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
271
|
+
return { valid: false, errors, warnings };
|
|
272
|
+
}
|
|
273
|
+
// Check environment is accessible
|
|
274
|
+
const dataverseClient = new DataverseClient({
|
|
275
|
+
environmentUrl: target.environmentUrl,
|
|
276
|
+
tokenManager: customerTokenManager,
|
|
277
|
+
clientId: this.config.clientId,
|
|
278
|
+
});
|
|
279
|
+
try {
|
|
280
|
+
await dataverseClient.querySolutions();
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
errors.push(`Environment not accessible: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
284
|
+
return { valid: false, errors, warnings };
|
|
285
|
+
}
|
|
286
|
+
// Check connection references if mappings provided
|
|
287
|
+
if (target.connectionMappings && target.connectionMappings.length > 0) {
|
|
288
|
+
const connectionOps = new ConnectionOperations(dataverseClient);
|
|
289
|
+
for (const mapping of target.connectionMappings) {
|
|
290
|
+
const connRef = await connectionOps.getConnectionReferenceByLogicalName(mapping.sourceLogicalName);
|
|
291
|
+
if (!connRef) {
|
|
292
|
+
warnings.push(`Connection reference not found: ${mapping.sourceLogicalName}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
valid: errors.length === 0,
|
|
298
|
+
errors,
|
|
299
|
+
warnings,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
errors.push(`Validation error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
304
|
+
return { valid: false, errors, warnings };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Check if an error indicates the app user is not registered.
|
|
309
|
+
* Prefers checking the structured error code; falls back to regex on the message.
|
|
310
|
+
*/
|
|
311
|
+
isAppUserNotRegisteredError(error) {
|
|
312
|
+
// Check typed error code first
|
|
313
|
+
if (error instanceof GdapError && error.code === ErrorCode.GDAP_APP_USER_NOT_REGISTERED) {
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
// Fallback to message matching for untyped errors from external sources
|
|
317
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
318
|
+
return (/user is not a member of the organization/i.test(errorMessage) ||
|
|
319
|
+
/not a member of.*environment/i.test(errorMessage) ||
|
|
320
|
+
/application is not registered as a user/i.test(errorMessage));
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Setup application user in an environment
|
|
324
|
+
*/
|
|
325
|
+
async setupApplicationUser(target, tokenManager) {
|
|
326
|
+
// We need the environment ID for the Power Platform Admin API
|
|
327
|
+
if (!target.environmentId) {
|
|
328
|
+
// Try to extract from URL (e.g., https://org.crm.dynamics.com -> org)
|
|
329
|
+
// This is a fallback - ideally environmentId should be provided in config
|
|
330
|
+
const match = target.environmentUrl.match(/https:\/\/([^.]+)\./);
|
|
331
|
+
if (!match) {
|
|
332
|
+
throw new GdapError(ErrorCode.GDAP_ENVIRONMENT_ID_MISSING, "Cannot auto-setup application user: environmentId not provided in target configuration.\n" +
|
|
333
|
+
"Please add 'environmentId' to your tenant configuration or set 'autoSetup: false' to disable auto-setup.", {
|
|
334
|
+
tenantId: target.tenantId,
|
|
335
|
+
tenantName: target.tenantName,
|
|
336
|
+
environmentUrl: target.environmentUrl,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
// Note: This is the org name, not the full environment ID
|
|
340
|
+
// The Admin API requires the full ID like: /providers/Microsoft.BusinessAppPlatform/scopes/admin/environments/{guid}
|
|
341
|
+
throw new GdapError(ErrorCode.GDAP_ENVIRONMENT_ID_MISSING, "Cannot auto-setup application user: environmentId not provided in target configuration.\n" +
|
|
342
|
+
"Please add 'environmentId' to your tenant configuration.\n" +
|
|
343
|
+
"You can find the environment ID in the Power Platform Admin Center URL when viewing the environment.", {
|
|
344
|
+
tenantId: target.tenantId,
|
|
345
|
+
tenantName: target.tenantName,
|
|
346
|
+
environmentUrl: target.environmentUrl,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
const adminClient = new PowerPlatformAdminClient({
|
|
350
|
+
tokenManager,
|
|
351
|
+
});
|
|
352
|
+
try {
|
|
353
|
+
const result = await adminClient.setupApplicationUser(target.environmentId, target.environmentUrl, this.config.clientId);
|
|
354
|
+
if (result.created) {
|
|
355
|
+
console.log(`\u2713 ${result.message}`);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
console.log(`\u2713 ${result.message}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
363
|
+
throw new GdapError(ErrorCode.GDAP_SETUP_FAILED, `Failed to auto-setup application user: ${errorMessage}\n\n` +
|
|
364
|
+
`You can disable auto-setup by setting 'autoSetup: false' in your tenant configuration,\n` +
|
|
365
|
+
`then follow the manual setup instructions.`, {
|
|
366
|
+
clientId: this.config.clientId,
|
|
367
|
+
tenantId: target.tenantId,
|
|
368
|
+
tenantName: target.tenantName,
|
|
369
|
+
environmentUrl: target.environmentUrl,
|
|
370
|
+
environmentId: target.environmentId,
|
|
371
|
+
}, { cause: error });
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=deployment-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-service.js","sourceRoot":"","sources":["../../src/services/deployment-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
* Drift Risk Analyzer
|
|
18
|
+
*
|
|
19
|
+
* Scores the risk of updating each drifted tenant by combining:
|
|
20
|
+
* - Version drift magnitude (how far behind)
|
|
21
|
+
* - Deployment history (last result, success rate, recency)
|
|
22
|
+
* - Tenant tags (production vs staging vs test)
|
|
23
|
+
*
|
|
24
|
+
* Produces a per-tenant recommendation: safe_to_update, review_recommended,
|
|
25
|
+
* update_risky, or do_not_update.
|
|
26
|
+
*/
|
|
27
|
+
import { TenantVersionStatus, SolutionVersionInfo } from "./version-checker.js";
|
|
28
|
+
import { TenantConfig } from "../config/schema.js";
|
|
29
|
+
export type DriftRiskLevel = "low" | "medium" | "high";
|
|
30
|
+
export type DriftRecommendation = "safe_to_update" | "review_recommended" | "update_risky" | "do_not_update" | "current";
|
|
31
|
+
export interface DriftRiskFactor {
|
|
32
|
+
name: string;
|
|
33
|
+
level: DriftRiskLevel;
|
|
34
|
+
weight: number;
|
|
35
|
+
description: string;
|
|
36
|
+
}
|
|
37
|
+
export interface TenantDriftAnalysis {
|
|
38
|
+
tenantId: string;
|
|
39
|
+
tenantName: string;
|
|
40
|
+
environmentUrl: string;
|
|
41
|
+
riskLevel: DriftRiskLevel;
|
|
42
|
+
riskScore: number;
|
|
43
|
+
recommendation: DriftRecommendation;
|
|
44
|
+
recommendationReason: string;
|
|
45
|
+
factors: DriftRiskFactor[];
|
|
46
|
+
versionStatus: TenantVersionStatus;
|
|
47
|
+
outdatedSolutions: SolutionVersionInfo[];
|
|
48
|
+
}
|
|
49
|
+
export interface FleetDriftAnalysis {
|
|
50
|
+
tenants: TenantDriftAnalysis[];
|
|
51
|
+
summary: {
|
|
52
|
+
total: number;
|
|
53
|
+
current: number;
|
|
54
|
+
safeToUpdate: number;
|
|
55
|
+
reviewRecommended: number;
|
|
56
|
+
risky: number;
|
|
57
|
+
doNotUpdate: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Deployment history for a single tenant, passed in by the caller.
|
|
62
|
+
* Keeps the DriftAnalyzer decoupled from Dataverse query logic.
|
|
63
|
+
*/
|
|
64
|
+
export interface TenantDeploymentHistory {
|
|
65
|
+
tenantId: string;
|
|
66
|
+
lastDeployResult: "success" | "failure" | null;
|
|
67
|
+
lastDeployDate: string | null;
|
|
68
|
+
totalDeploys: number;
|
|
69
|
+
successfulDeploys: number;
|
|
70
|
+
}
|
|
71
|
+
export declare class DriftAnalyzer {
|
|
72
|
+
/**
|
|
73
|
+
* Analyze drift risk for a single tenant
|
|
74
|
+
*/
|
|
75
|
+
analyzeTenant(tenant: TenantConfig, versionStatus: TenantVersionStatus, history?: TenantDeploymentHistory): TenantDriftAnalysis;
|
|
76
|
+
/**
|
|
77
|
+
* Analyze drift risk for a fleet of tenants
|
|
78
|
+
*/
|
|
79
|
+
analyzeFleet(tenants: TenantConfig[], versionStatuses: TenantVersionStatus[], histories?: Map<string, TenantDeploymentHistory>): FleetDriftAnalysis;
|
|
80
|
+
private calculateScore;
|
|
81
|
+
private scoreToLevel;
|
|
82
|
+
private getRecommendation;
|
|
83
|
+
private getTopRiskDescription;
|
|
84
|
+
}
|
|
85
|
+
export declare const driftAnalyzer: DriftAnalyzer;
|
|
86
|
+
//# sourceMappingURL=drift-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift-analyzer.d.ts","sourceRoot":"","sources":["../../src/services/drift-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMnD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvD,MAAM,MAAM,mBAAmB,GAC3B,gBAAgB,GAChB,oBAAoB,GACpB,cAAc,GACd,eAAe,GACf,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,mBAAmB,CAAC;IACpC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,aAAa,EAAE,mBAAmB,CAAC;IACnC,iBAAiB,EAAE,mBAAmB,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC;IAC/C,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAsBD,qBAAa,aAAa;IACxB;;OAEG;IACH,aAAa,CACX,MAAM,EAAE,YAAY,EACpB,aAAa,EAAE,mBAAmB,EAClC,OAAO,CAAC,EAAE,uBAAuB,GAChC,mBAAmB;IA0JtB;;OAEG;IACH,YAAY,CACV,OAAO,EAAE,YAAY,EAAE,EACvB,eAAe,EAAE,mBAAmB,EAAE,EACtC,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,GAC/C,kBAAkB;IAwBrB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,iBAAiB;IA4CzB,OAAO,CAAC,qBAAqB;CAQ9B;AAGD,eAAO,MAAM,aAAa,eAAsB,CAAC"}
|