@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.
Files changed (226) hide show
  1. package/LICENSE +198 -0
  2. package/dist/auth/device-code-login.d.ts +40 -0
  3. package/dist/auth/device-code-login.d.ts.map +1 -0
  4. package/dist/auth/device-code-login.js +59 -0
  5. package/dist/auth/device-code-login.js.map +1 -0
  6. package/dist/auth/gdap-client.d.ts +81 -0
  7. package/dist/auth/gdap-client.d.ts.map +1 -0
  8. package/dist/auth/gdap-client.js +128 -0
  9. package/dist/auth/gdap-client.js.map +1 -0
  10. package/dist/auth/index.d.ts +19 -0
  11. package/dist/auth/index.d.ts.map +1 -0
  12. package/dist/auth/index.js +19 -0
  13. package/dist/auth/index.js.map +1 -0
  14. package/dist/auth/token-manager.d.ts +54 -0
  15. package/dist/auth/token-manager.d.ts.map +1 -0
  16. package/dist/auth/token-manager.js +150 -0
  17. package/dist/auth/token-manager.js.map +1 -0
  18. package/dist/client.d.ts +27 -0
  19. package/dist/client.d.ts.map +1 -0
  20. package/dist/client.js +27 -0
  21. package/dist/client.js.map +1 -0
  22. package/dist/config/client.d.ts +24 -0
  23. package/dist/config/client.d.ts.map +1 -0
  24. package/dist/config/client.js +18 -0
  25. package/dist/config/client.js.map +1 -0
  26. package/dist/config/index.d.ts +18 -0
  27. package/dist/config/index.d.ts.map +1 -0
  28. package/dist/config/index.js +18 -0
  29. package/dist/config/index.js.map +1 -0
  30. package/dist/config/loader.d.ts +81 -0
  31. package/dist/config/loader.d.ts.map +1 -0
  32. package/dist/config/loader.js +271 -0
  33. package/dist/config/loader.js.map +1 -0
  34. package/dist/config/schema.d.ts +751 -0
  35. package/dist/config/schema.d.ts.map +1 -0
  36. package/dist/config/schema.js +556 -0
  37. package/dist/config/schema.js.map +1 -0
  38. package/dist/constants.d.ts +116 -0
  39. package/dist/constants.d.ts.map +1 -0
  40. package/dist/constants.js +170 -0
  41. package/dist/constants.js.map +1 -0
  42. package/dist/dataverse/agent-resolver.d.ts +98 -0
  43. package/dist/dataverse/agent-resolver.d.ts.map +1 -0
  44. package/dist/dataverse/agent-resolver.js +185 -0
  45. package/dist/dataverse/agent-resolver.js.map +1 -0
  46. package/dist/dataverse/client.d.ts +104 -0
  47. package/dist/dataverse/client.d.ts.map +1 -0
  48. package/dist/dataverse/client.js +272 -0
  49. package/dist/dataverse/client.js.map +1 -0
  50. package/dist/dataverse/connection-refs.d.ts +115 -0
  51. package/dist/dataverse/connection-refs.d.ts.map +1 -0
  52. package/dist/dataverse/connection-refs.js +203 -0
  53. package/dist/dataverse/connection-refs.js.map +1 -0
  54. package/dist/dataverse/index.d.ts +20 -0
  55. package/dist/dataverse/index.d.ts.map +1 -0
  56. package/dist/dataverse/index.js +20 -0
  57. package/dist/dataverse/index.js.map +1 -0
  58. package/dist/dataverse/solution-ops.d.ts +100 -0
  59. package/dist/dataverse/solution-ops.d.ts.map +1 -0
  60. package/dist/dataverse/solution-ops.js +288 -0
  61. package/dist/dataverse/solution-ops.js.map +1 -0
  62. package/dist/errors.d.ts +171 -0
  63. package/dist/errors.d.ts.map +1 -0
  64. package/dist/errors.js +178 -0
  65. package/dist/errors.js.map +1 -0
  66. package/dist/index.d.ts +27 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +40 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/mock/demo-data.d.ts +213 -0
  71. package/dist/mock/demo-data.d.ts.map +1 -0
  72. package/dist/mock/demo-data.js +1096 -0
  73. package/dist/mock/demo-data.js.map +1 -0
  74. package/dist/mock/demo-deployment-store.d.ts +77 -0
  75. package/dist/mock/demo-deployment-store.d.ts.map +1 -0
  76. package/dist/mock/demo-deployment-store.js +85 -0
  77. package/dist/mock/demo-deployment-store.js.map +1 -0
  78. package/dist/powerplatform/admin-client.d.ts +226 -0
  79. package/dist/powerplatform/admin-client.d.ts.map +1 -0
  80. package/dist/powerplatform/admin-client.js +315 -0
  81. package/dist/powerplatform/admin-client.js.map +1 -0
  82. package/dist/powerplatform/index.d.ts +18 -0
  83. package/dist/powerplatform/index.d.ts.map +1 -0
  84. package/dist/powerplatform/index.js +18 -0
  85. package/dist/powerplatform/index.js.map +1 -0
  86. package/dist/powerplatform/tenant-discovery.d.ts +100 -0
  87. package/dist/powerplatform/tenant-discovery.d.ts.map +1 -0
  88. package/dist/powerplatform/tenant-discovery.js +205 -0
  89. package/dist/powerplatform/tenant-discovery.js.map +1 -0
  90. package/dist/preconditions/check.d.ts +41 -0
  91. package/dist/preconditions/check.d.ts.map +1 -0
  92. package/dist/preconditions/check.js +173 -0
  93. package/dist/preconditions/check.js.map +1 -0
  94. package/dist/preconditions/index.d.ts +20 -0
  95. package/dist/preconditions/index.d.ts.map +1 -0
  96. package/dist/preconditions/index.js +20 -0
  97. package/dist/preconditions/index.js.map +1 -0
  98. package/dist/preconditions/loader.d.ts +33 -0
  99. package/dist/preconditions/loader.d.ts.map +1 -0
  100. package/dist/preconditions/loader.js +65 -0
  101. package/dist/preconditions/loader.js.map +1 -0
  102. package/dist/preconditions/schema.d.ts +103 -0
  103. package/dist/preconditions/schema.d.ts.map +1 -0
  104. package/dist/preconditions/schema.js +93 -0
  105. package/dist/preconditions/schema.js.map +1 -0
  106. package/dist/preconditions/types.d.ts +118 -0
  107. package/dist/preconditions/types.d.ts.map +1 -0
  108. package/dist/preconditions/types.js +17 -0
  109. package/dist/preconditions/types.js.map +1 -0
  110. package/dist/queue/index.d.ts +17 -0
  111. package/dist/queue/index.d.ts.map +1 -0
  112. package/dist/queue/index.js +17 -0
  113. package/dist/queue/index.js.map +1 -0
  114. package/dist/queue/memory-queue.d.ts +86 -0
  115. package/dist/queue/memory-queue.d.ts.map +1 -0
  116. package/dist/queue/memory-queue.js +221 -0
  117. package/dist/queue/memory-queue.js.map +1 -0
  118. package/dist/services/audit-log.d.ts +59 -0
  119. package/dist/services/audit-log.d.ts.map +1 -0
  120. package/dist/services/audit-log.js +193 -0
  121. package/dist/services/audit-log.js.map +1 -0
  122. package/dist/services/auth-error-parser.d.ts +36 -0
  123. package/dist/services/auth-error-parser.d.ts.map +1 -0
  124. package/dist/services/auth-error-parser.js +90 -0
  125. package/dist/services/auth-error-parser.js.map +1 -0
  126. package/dist/services/deployment-doctor.d.ts +109 -0
  127. package/dist/services/deployment-doctor.d.ts.map +1 -0
  128. package/dist/services/deployment-doctor.js +476 -0
  129. package/dist/services/deployment-doctor.js.map +1 -0
  130. package/dist/services/deployment-notifications.d.ts +41 -0
  131. package/dist/services/deployment-notifications.d.ts.map +1 -0
  132. package/dist/services/deployment-notifications.js +161 -0
  133. package/dist/services/deployment-notifications.js.map +1 -0
  134. package/dist/services/deployment-progress.d.ts +89 -0
  135. package/dist/services/deployment-progress.d.ts.map +1 -0
  136. package/dist/services/deployment-progress.js +244 -0
  137. package/dist/services/deployment-progress.js.map +1 -0
  138. package/dist/services/deployment-service.d.ts +97 -0
  139. package/dist/services/deployment-service.d.ts.map +1 -0
  140. package/dist/services/deployment-service.js +375 -0
  141. package/dist/services/deployment-service.js.map +1 -0
  142. package/dist/services/drift-analyzer.d.ts +86 -0
  143. package/dist/services/drift-analyzer.d.ts.map +1 -0
  144. package/dist/services/drift-analyzer.js +273 -0
  145. package/dist/services/drift-analyzer.js.map +1 -0
  146. package/dist/services/environment-setup.d.ts +97 -0
  147. package/dist/services/environment-setup.d.ts.map +1 -0
  148. package/dist/services/environment-setup.js +250 -0
  149. package/dist/services/environment-setup.js.map +1 -0
  150. package/dist/services/health-check.d.ts +168 -0
  151. package/dist/services/health-check.d.ts.map +1 -0
  152. package/dist/services/health-check.js +705 -0
  153. package/dist/services/health-check.js.map +1 -0
  154. package/dist/services/index.d.ts +39 -0
  155. package/dist/services/index.d.ts.map +1 -0
  156. package/dist/services/index.js +39 -0
  157. package/dist/services/index.js.map +1 -0
  158. package/dist/services/logger.d.ts +139 -0
  159. package/dist/services/logger.d.ts.map +1 -0
  160. package/dist/services/logger.js +268 -0
  161. package/dist/services/logger.js.map +1 -0
  162. package/dist/services/notification-service.d.ts +55 -0
  163. package/dist/services/notification-service.d.ts.map +1 -0
  164. package/dist/services/notification-service.js +184 -0
  165. package/dist/services/notification-service.js.map +1 -0
  166. package/dist/services/risk-analyzer.d.ts +252 -0
  167. package/dist/services/risk-analyzer.d.ts.map +1 -0
  168. package/dist/services/risk-analyzer.js +866 -0
  169. package/dist/services/risk-analyzer.js.map +1 -0
  170. package/dist/services/rollback.d.ts +57 -0
  171. package/dist/services/rollback.d.ts.map +1 -0
  172. package/dist/services/rollback.js +270 -0
  173. package/dist/services/rollback.js.map +1 -0
  174. package/dist/services/scheduler.d.ts +80 -0
  175. package/dist/services/scheduler.d.ts.map +1 -0
  176. package/dist/services/scheduler.js +350 -0
  177. package/dist/services/scheduler.js.map +1 -0
  178. package/dist/services/secrets.d.ts +31 -0
  179. package/dist/services/secrets.d.ts.map +1 -0
  180. package/dist/services/secrets.js +206 -0
  181. package/dist/services/secrets.js.map +1 -0
  182. package/dist/services/settings-service.d.ts +132 -0
  183. package/dist/services/settings-service.d.ts.map +1 -0
  184. package/dist/services/settings-service.js +378 -0
  185. package/dist/services/settings-service.js.map +1 -0
  186. package/dist/services/solution-diff.d.ts +127 -0
  187. package/dist/services/solution-diff.d.ts.map +1 -0
  188. package/dist/services/solution-diff.js +260 -0
  189. package/dist/services/solution-diff.js.map +1 -0
  190. package/dist/services/solution-mode-detector.d.ts +35 -0
  191. package/dist/services/solution-mode-detector.d.ts.map +1 -0
  192. package/dist/services/solution-mode-detector.js +84 -0
  193. package/dist/services/solution-mode-detector.js.map +1 -0
  194. package/dist/services/tenant-resolver.d.ts +55 -0
  195. package/dist/services/tenant-resolver.d.ts.map +1 -0
  196. package/dist/services/tenant-resolver.js +126 -0
  197. package/dist/services/tenant-resolver.js.map +1 -0
  198. package/dist/services/unmanaged-customizations.d.ts +104 -0
  199. package/dist/services/unmanaged-customizations.d.ts.map +1 -0
  200. package/dist/services/unmanaged-customizations.js +521 -0
  201. package/dist/services/unmanaged-customizations.js.map +1 -0
  202. package/dist/services/url-templater.d.ts +184 -0
  203. package/dist/services/url-templater.d.ts.map +1 -0
  204. package/dist/services/url-templater.js +327 -0
  205. package/dist/services/url-templater.js.map +1 -0
  206. package/dist/services/version-checker.d.ts +108 -0
  207. package/dist/services/version-checker.d.ts.map +1 -0
  208. package/dist/services/version-checker.js +403 -0
  209. package/dist/services/version-checker.js.map +1 -0
  210. package/dist/services/waves.d.ts +90 -0
  211. package/dist/services/waves.d.ts.map +1 -0
  212. package/dist/services/waves.js +222 -0
  213. package/dist/services/waves.js.map +1 -0
  214. package/dist/services/webhook.d.ts +95 -0
  215. package/dist/services/webhook.d.ts.map +1 -0
  216. package/dist/services/webhook.js +244 -0
  217. package/dist/services/webhook.js.map +1 -0
  218. package/dist/utils/deployment-tools.d.ts +110 -0
  219. package/dist/utils/deployment-tools.d.ts.map +1 -0
  220. package/dist/utils/deployment-tools.js +121 -0
  221. package/dist/utils/deployment-tools.js.map +1 -0
  222. package/dist/utils/index.d.ts +17 -0
  223. package/dist/utils/index.d.ts.map +1 -0
  224. package/dist/utils/index.js +18 -0
  225. package/dist/utils/index.js.map +1 -0
  226. 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"}