@uipath/solution-tool 1.203.0-preview.205 → 1.204.0-preview.206

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 (76) hide show
  1. package/README.md +2 -2
  2. package/dist/THIRD-PARTY-NOTICES.md +42 -4
  3. package/dist/deploy-delete-service-y9dwehmn.js +22 -0
  4. package/dist/deploy-status-service-nmhnnjmy.js +256 -0
  5. package/dist/deploy.d.ts +11 -4
  6. package/dist/deploy.js +19 -7
  7. package/dist/deployment-search-eb337bjh.js +49 -0
  8. package/dist/{embedded-file-reader-xxqe8vs8.js → embedded-file-reader-rf2g1kfj.js} +2 -2
  9. package/dist/feed-resolver-dmtnswcc.js +27 -0
  10. package/dist/feed-scope-failure-e2yaqfg2.js +18 -0
  11. package/dist/feed-session-sxga31vn.js +17 -0
  12. package/dist/index.js +27 -18
  13. package/dist/init.js +10 -7
  14. package/dist/{list-pytnrana.js → list-rbjqgz6s.js} +9 -6
  15. package/dist/pack.js +14 -11
  16. package/dist/{packager-tool-vas0xg5h.js → packager-tool-2cntqvdv.js} +5 -3
  17. package/dist/{packager-tool-1haahq17.js → packager-tool-3enm2h28.js} +5 -5
  18. package/dist/{packager-tool-2syrt51a.js → packager-tool-3fv6zc86.js} +1062 -825
  19. package/dist/packager-tool-3fyq6wjs.js +5889 -0
  20. package/dist/{packager-tool-k4mskzww.js → packager-tool-5dzjsw5q.js} +3 -3
  21. package/dist/{packager-tool-0f0wt9vh.js → packager-tool-5fjp60dk.js} +3071 -2794
  22. package/dist/{packager-tool-1qnyt7sm.js → packager-tool-752zvh64.js} +756 -359
  23. package/dist/{packager-tool-bkwnetqn.js → packager-tool-83rzavkx.js} +383 -88
  24. package/dist/{packager-tool-7znqtw3f.js → packager-tool-9vvdgbay.js} +8 -6
  25. package/dist/packager-tool-b8pppqbb.js +172 -0
  26. package/dist/packager-tool-bqre28m1.js +43 -0
  27. package/dist/packager-tool-dh0m3ebf.js +173 -0
  28. package/dist/packager-tool-f5gq77m5.js +28 -0
  29. package/dist/{packager-tool-nzghfa48.js → packager-tool-fv7xyzg2.js} +550 -2
  30. package/dist/{packager-tool-3jrq7smt.js → packager-tool-gb35b4qs.js} +206 -289
  31. package/dist/{packager-tool-7rarcemd.js → packager-tool-he7ak44z.js} +16 -74
  32. package/dist/packager-tool-myn57mc3.js +322 -0
  33. package/dist/{packager-tool-jmpgr1an.js → packager-tool-n1nzj2b9.js} +1008 -647
  34. package/dist/packager-tool-n6yb6zp9.js +113 -0
  35. package/dist/{packager-tool-wkj58797.js → packager-tool-qgaqqq41.js} +320 -151
  36. package/dist/{packager-tool-resolver-fmjr60x8.js → packager-tool-resolver-2cbxyq6k.js} +6 -5
  37. package/dist/{packager-tool-2kvztdcy.js → packager-tool-t12hj6pd.js} +1022 -1342
  38. package/dist/{packager-tool-znakt6yw.js → packager-tool-vh4ng74p.js} +8 -6
  39. package/dist/packager-tool-vmsxq1pc.js +104 -0
  40. package/dist/packager-tool-w6jr4638.js +166 -0
  41. package/dist/packager-tool-zf3929se.js +237 -0
  42. package/dist/packager-tool-zns6n8zp.js +837 -0
  43. package/dist/packager-tool-zw3036b8.js +37 -0
  44. package/dist/packager-tool.js +2 -2
  45. package/dist/prepare-solution-resources-p3gzdecy.js +25 -0
  46. package/dist/{project-contributions-cvttys34.js → project-contributions-txe8v6sm.js} +12 -9
  47. package/dist/publish.js +12 -7
  48. package/dist/resource.js +9 -6
  49. package/dist/services/activation.d.ts +17 -2
  50. package/dist/services/deploy-activate-service.d.ts +10 -0
  51. package/dist/services/deploy-delete-service.d.ts +82 -0
  52. package/dist/services/deploy-list-service.d.ts +15 -45
  53. package/dist/services/deploy-run-service.d.ts +36 -23
  54. package/dist/services/deploy-upgrade-service.d.ts +198 -39
  55. package/dist/services/deployment-feed-locator.d.ts +50 -12
  56. package/dist/services/deployment-search-client.d.ts +55 -0
  57. package/dist/services/deployment-search.d.ts +87 -34
  58. package/dist/services/deployment-state.d.ts +119 -0
  59. package/dist/services/feed-resolver.d.ts +31 -0
  60. package/dist/services/feed-session.d.ts +70 -0
  61. package/dist/services/folder-helper.d.ts +4 -27
  62. package/dist/services/http-status.d.ts +9 -0
  63. package/dist/services/incomplete-feed-sweep.d.ts +77 -0
  64. package/dist/services/legacy-deployment-search-v3.d.ts +23 -0
  65. package/dist/services/packages-list-service.d.ts +5 -0
  66. package/dist/services/pipeline-deploy-poll.d.ts +69 -0
  67. package/dist/services/publish-service.d.ts +14 -16
  68. package/dist/services/search-failure.d.ts +27 -0
  69. package/dist/templates/AGENTS.md +60 -20
  70. package/dist/tool.js +27 -18
  71. package/dist/utils/deployment-errors.d.ts +57 -0
  72. package/package.json +2 -2
  73. package/dist/packager-tool-364pcg21.js +0 -51960
  74. package/dist/packager-tool-jz2wbfjz.js +0 -2275
  75. package/dist/prepare-solution-resources-wds3r8bq.js +0 -22
  76. package/dist/services/personal-workspace-deploy.d.ts +0 -49
@@ -0,0 +1,837 @@
1
+ import {
2
+ NugetConstants,
3
+ NugetPackager,
4
+ Path,
5
+ ProjectTool,
6
+ SolutionTool,
7
+ TemporaryStorageService,
8
+ ToolResult,
9
+ ensureProjectId,
10
+ toolsFactoryRepository,
11
+ writeOrBackfillOperateProjectId
12
+ } from "./packager-tool-fv7xyzg2.js";
13
+
14
+ // ../packager/packager-tool-connector/src/connector-tool.ts
15
+ class ConnectorTool extends ProjectTool {
16
+ static AppFolderName = "app";
17
+ _temporaryStorage;
18
+ constructor(fileSystem, logger) {
19
+ super(fileSystem, logger);
20
+ this._temporaryStorage = new TemporaryStorageService(fileSystem);
21
+ }
22
+ async restoreAsync(_options, _cancellationToken) {
23
+ this.logger.info("Restore operation is not required for Connector projects");
24
+ return ToolResult.success();
25
+ }
26
+ async validateAsync(_options, _cancellationToken) {
27
+ this.logger.info("Validate operation is not required for Connector projects");
28
+ return ToolResult.success();
29
+ }
30
+ async buildAsync(options, _cancellationToken) {
31
+ const tempFolder = await this._temporaryStorage.getTempFolderPath();
32
+ const localBuildFolder = Path.join(tempFolder, NugetConstants.OutputFolderName);
33
+ const appProjectFolder = Path.join(options.projectPath, ConnectorTool.AppFolderName);
34
+ const destinationFolder = Path.join(localBuildFolder, NugetConstants.ContentFolderName, ConnectorTool.AppFolderName);
35
+ try {
36
+ this.logger.progress("Copying app folder...");
37
+ await this.copyDirectory(appProjectFolder, destinationFolder);
38
+ this.logger.progress("Creating operate.json file...");
39
+ await this.createOperateFile(options, localBuildFolder);
40
+ this.logger.progress("Creating package-descriptor.json file...");
41
+ await this.createPackageDescriptor(localBuildFolder);
42
+ return new ToolResult("SUCCESS" /* Success */, "done", [
43
+ localBuildFolder
44
+ ]);
45
+ } catch (error) {
46
+ const errorMessage = error instanceof Error ? error.toString() : String(error);
47
+ this.logger.error(errorMessage);
48
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, "An error occurred while building Connector project");
49
+ }
50
+ }
51
+ async packAsync(options, cancellationToken) {
52
+ const buildResult = await this.buildAsync(options, cancellationToken);
53
+ if (!buildResult.isSuccess) {
54
+ return buildResult;
55
+ }
56
+ const localBuildFolder = buildResult.packages[0];
57
+ try {
58
+ this.logger.progress("Creating NuGet package...");
59
+ const nupkgFileName = `${options.package.id}.${options.package.version}.nupkg`;
60
+ const nupkgPath = Path.join(options.outputPath, nupkgFileName);
61
+ const packager = new NugetPackager(this.fileSystem);
62
+ const result = await packager.packAsync(localBuildFolder, options.package, nupkgPath);
63
+ this.logger.progress("Package created successfully");
64
+ return new ToolResult("SUCCESS" /* Success */, "done", [
65
+ result.outputPath
66
+ ]);
67
+ } catch (error) {
68
+ const errorMessage = error instanceof Error ? error.toString() : String(error);
69
+ this.logger.error(errorMessage);
70
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, "An error occurred while packing Connector project");
71
+ }
72
+ }
73
+ async dispose() {
74
+ this.logger.info("Disposing Connector Tool");
75
+ try {
76
+ await this._temporaryStorage.cleanup();
77
+ } catch {}
78
+ }
79
+ async createOperateFile(options, localBuildFolder) {
80
+ const contentFolder = Path.join(localBuildFolder, NugetConstants.ContentFolderName);
81
+ const operateJsonFilePath = Path.join(contentFolder, NugetConstants.OperateFileName);
82
+ const projectId = options.projectStorageId ?? await this.resolveConnectorProjectId(options.projectPath);
83
+ await writeOrBackfillOperateProjectId(operateJsonFilePath, projectId, this.fileSystem, () => this.fileSystem.writeFile(operateJsonFilePath, JSON.stringify({
84
+ $schema: "https://cloud.uipath.com/draft/2024-12/operate",
85
+ contentType: "Connector" /* Connector */,
86
+ projectId,
87
+ main: "",
88
+ targetFramework: "Portable",
89
+ runtimeOptions: {
90
+ isAttended: false,
91
+ requiresUserInteraction: false
92
+ }
93
+ }, null, 2)));
94
+ }
95
+ async resolveConnectorProjectId(projectPath) {
96
+ const operatePath = Path.join(projectPath, "operate.json");
97
+ const projectFilePath = Path.join(projectPath, "project.json");
98
+ const hasAnchor = await this.fileSystem.exists(operatePath) || await this.fileSystem.exists(projectFilePath);
99
+ if (hasAnchor) {
100
+ return ensureProjectId(projectPath, this.fileSystem);
101
+ }
102
+ const id = crypto.randomUUID();
103
+ await this.fileSystem.writeFile(projectFilePath, `${JSON.stringify({ projectId: id }, null, 2)}
104
+ `);
105
+ return id;
106
+ }
107
+ async createPackageDescriptor(localBuildFolder) {
108
+ const packageDescriptorPath = Path.join(localBuildFolder, NugetConstants.ContentFolderName, NugetConstants.PackageDescriptorFileName);
109
+ const exists = await this.fileSystem.exists(packageDescriptorPath);
110
+ if (exists) {
111
+ return;
112
+ }
113
+ const descriptor = {
114
+ $schema: "https://cloud.uipath.com/draft/2024-12/package-descriptor",
115
+ files: {
116
+ [NugetConstants.OperateFileName]: Path.join(NugetConstants.ContentFolderName, NugetConstants.OperateFileName)
117
+ }
118
+ };
119
+ await this.fileSystem.writeFile(packageDescriptorPath, JSON.stringify(descriptor, null, 2));
120
+ }
121
+ async copyDirectory(sourcePath, destinationPath) {
122
+ await this.fileSystem.mkdir(destinationPath);
123
+ const entries = await this.fileSystem.readdir(sourcePath);
124
+ for (const entry of entries) {
125
+ const sourceEntry = Path.join(sourcePath, entry);
126
+ const destinationEntry = Path.join(destinationPath, entry);
127
+ const stat = await this.fileSystem.stat(sourceEntry);
128
+ if (stat?.isDirectory()) {
129
+ await this.copyDirectory(sourceEntry, destinationEntry);
130
+ } else if (stat?.isFile()) {
131
+ const content = await this.fileSystem.readFile(sourceEntry);
132
+ if (content) {
133
+ await this.fileSystem.writeFile(destinationEntry, content);
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ // ../packager/packager-tool-connector/src/connector-tool-factory.ts
141
+ class ConnectorToolFactory {
142
+ supportedTypes = ["Connector" /* Connector */];
143
+ async createAsync(logger, fileSystem) {
144
+ return new ConnectorTool(fileSystem, logger);
145
+ }
146
+ }
147
+ // ../../node_modules/@uipath/resource-builder-tool/dist/index.js
148
+ function _define_property(obj, key, value) {
149
+ if (key in obj)
150
+ Object.defineProperty(obj, key, {
151
+ value,
152
+ enumerable: true,
153
+ configurable: true,
154
+ writable: true
155
+ });
156
+ else
157
+ obj[key] = value;
158
+ return obj;
159
+ }
160
+ var KNOWN_ARCHIVE_FILE_NAMES = {
161
+ packageInfoJsonFileName: "packageInfo.json",
162
+ metadataJsonFileName: "solutionMetadata.json"
163
+ };
164
+ var KNOWN_ARCHIVE_FOLDERS = {
165
+ files: "files",
166
+ resources: "resources"
167
+ };
168
+ var PACKAGE_DEFAULTS = {
169
+ currentVersion: "v1",
170
+ defaultPackageVersion: "1.0.0",
171
+ defaultAuthorName: "UiPath",
172
+ unifiedBuildPackageType: "unified",
173
+ currentDocVersion: "1.0.0",
174
+ rootFolderName: "solution_folder"
175
+ };
176
+ var JWT_CLAIMS = {
177
+ firstName: "first_name",
178
+ lastName: "last_name",
179
+ email: "email",
180
+ userId: "sub",
181
+ partition: "prt_id"
182
+ };
183
+ var RESILIENCE_DEFAULTS = {
184
+ maxRetryAttempts: 3,
185
+ retryIntervalMs: 1000,
186
+ maxRedirectRetries: 10
187
+ };
188
+ var MAX_DOWNLOAD_CONCURRENCY = 8;
189
+ var RETRIABLE_STATUS_CODES = [
190
+ 500,
191
+ 502,
192
+ 503,
193
+ 504
194
+ ];
195
+ var INVALID_FILE_NAME_CHARS = /[<>:"/\\|?*\x00-\x1f\s]/g;
196
+ var MAX_SERVER_MESSAGE_LENGTH = 100;
197
+ var MAX_BUILD_OUTPUT_SIZE_BYTES = 524288000;
198
+
199
+ class OperationCancelledException extends Error {
200
+ constructor(message) {
201
+ super(message ?? "The operation was cancelled");
202
+ this.name = "OperationCancelledException";
203
+ if (Error.captureStackTrace)
204
+ Error.captureStackTrace(this, OperationCancelledException);
205
+ }
206
+ }
207
+ function mapHttpStatusCodeToReason(status) {
208
+ switch (status) {
209
+ case 404:
210
+ return "NotFound";
211
+ case 401:
212
+ return "Unauthorized";
213
+ case 403:
214
+ return "Forbidden";
215
+ case 400:
216
+ return "BadRequest";
217
+ case 408:
218
+ case 504:
219
+ return "Timeout";
220
+ default:
221
+ if (status >= 500)
222
+ return "ServerError";
223
+ return "Unknown";
224
+ }
225
+ }
226
+ function truncateMessage(message, maxLength) {
227
+ if (!message)
228
+ return message;
229
+ if (message.length <= maxLength)
230
+ return message;
231
+ return message.substring(0, maxLength) + "...";
232
+ }
233
+ function buildFailureMessage(failures) {
234
+ const lines = [
235
+ `Failed to download ${failures.length} file(s):`
236
+ ];
237
+ for (const failure of failures)
238
+ lines.push(` - FileKey: ${failure.fileKey}, Service: ${failure.service}, Url: ${failure.externalUrl}, Reason: ${failure.reason}, Message: ${failure.errorMessage ?? ""}`);
239
+ return lines.join(`
240
+ `);
241
+ }
242
+ function isArtefactResource(resource) {
243
+ return resource.projectKey != null && resource.projectKey.trim() !== "";
244
+ }
245
+ var JSON_INDENT = 2;
246
+ function shouldExcludeValue(value) {
247
+ return value == null;
248
+ }
249
+ function serializeJson(obj) {
250
+ return JSON.stringify(obj, (_key, value) => shouldExcludeValue(value) ? undefined : value, JSON_INDENT);
251
+ }
252
+ function decodeJwtPayload(token) {
253
+ try {
254
+ const parts = token.split(".");
255
+ if (parts.length !== 3)
256
+ return null;
257
+ const payload = parts[1];
258
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
259
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
260
+ const decoded = atob(padded);
261
+ return JSON.parse(decoded);
262
+ } catch {
263
+ return null;
264
+ }
265
+ }
266
+ function extractDataFromAccessToken(accessToken) {
267
+ if (!accessToken)
268
+ return {};
269
+ const payload = decodeJwtPayload(accessToken);
270
+ if (!payload)
271
+ return {};
272
+ const getString = (key) => {
273
+ const value = payload[key];
274
+ return typeof value == "string" && value.trim() !== "" ? value : undefined;
275
+ };
276
+ return {
277
+ email: getString(JWT_CLAIMS.email),
278
+ firstName: getString(JWT_CLAIMS.firstName),
279
+ lastName: getString(JWT_CLAIMS.lastName),
280
+ userId: getString(JWT_CLAIMS.userId),
281
+ partitionId: getString(JWT_CLAIMS.partition)
282
+ };
283
+ }
284
+ function isRetriableStatusCode(status) {
285
+ return RETRIABLE_STATUS_CODES.includes(status);
286
+ }
287
+ function isRedirectStatusCode(status) {
288
+ return status === 302 || status === 303;
289
+ }
290
+ function isClientError(status) {
291
+ return status >= 400 && status < 500;
292
+ }
293
+ function delay(ms, cancellationToken) {
294
+ return new Promise((resolve, reject) => {
295
+ if (cancellationToken?.aborted)
296
+ return void reject(new OperationCancelledException);
297
+ const timeoutId = setTimeout(resolve, ms);
298
+ cancellationToken?.addEventListener("abort", () => {
299
+ clearTimeout(timeoutId);
300
+ reject(new OperationCancelledException);
301
+ }, {
302
+ once: true
303
+ });
304
+ });
305
+ }
306
+ function throwIfCancelled(cancellationToken) {
307
+ if (cancellationToken?.aborted)
308
+ throw new OperationCancelledException;
309
+ }
310
+
311
+ class Semaphore {
312
+ async acquire() {
313
+ if (this.permits > 0)
314
+ return void this.permits--;
315
+ return new Promise((resolve) => {
316
+ this.waitQueue.push(resolve);
317
+ });
318
+ }
319
+ release() {
320
+ const next = this.waitQueue.shift();
321
+ if (next)
322
+ next();
323
+ else
324
+ this.permits++;
325
+ }
326
+ constructor(permits) {
327
+ _define_property(this, "permits", undefined);
328
+ _define_property(this, "waitQueue", []);
329
+ this.permits = permits;
330
+ }
331
+ }
332
+
333
+ class ResourceBuilderTool extends SolutionTool {
334
+ async buildAsync(options, cancellationToken) {
335
+ this.logger.info("Build starting.");
336
+ this.inputPath = Path.dirname(options.solutionFilePath);
337
+ try {
338
+ throwIfCancelled(cancellationToken);
339
+ const accessToken = options.connection?.accessToken;
340
+ const tokenData = extractDataFromAccessToken(accessToken);
341
+ const existingResources = await this.readFromDirectory(KNOWN_ARCHIVE_FOLDERS.resources, cancellationToken);
342
+ this.logger.info(`Read ${existingResources.length} existing resources from ${KNOWN_ARCHIVE_FOLDERS.resources} directory.`);
343
+ if (existingResources && existingResources.length > 0) {
344
+ throwIfCancelled(cancellationToken);
345
+ const filteredResources = this.filterResources(existingResources, options);
346
+ await this.writeResources(filteredResources, options, cancellationToken);
347
+ } else
348
+ throw new Error("No resources found to build.");
349
+ await this.writePackageFiles(options, tokenData, cancellationToken);
350
+ const sizeLimitError = await this.enforceOutputSizeLimit(options.outputPath);
351
+ if (sizeLimitError)
352
+ return sizeLimitError;
353
+ this.logger.info("Build finished.");
354
+ return ToolResult.success();
355
+ } catch (error) {
356
+ const message = error instanceof Error ? error.message : String(error);
357
+ this.logger.error(`Build failed: ${message}`);
358
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, `Build failed: ${message}`);
359
+ }
360
+ }
361
+ async enforceOutputSizeLimit(outputPath) {
362
+ const filesDirectory = Path.join(outputPath, KNOWN_ARCHIVE_FOLDERS.files);
363
+ if (!await this.fileSystem.exists(filesDirectory))
364
+ return null;
365
+ const totalBytes = await this.getTotalDirectorySize(filesDirectory);
366
+ if (totalBytes <= MAX_BUILD_OUTPUT_SIZE_BYTES)
367
+ return null;
368
+ const maxMb = Math.floor(MAX_BUILD_OUTPUT_SIZE_BYTES / 1024 / 1024);
369
+ const currentMb = Math.floor(totalBytes / 1024 / 1024);
370
+ const message = `The built solution exceeds the maximum allowed size of ${maxMb} MB (current size: ${currentMb} MB). Solutions larger than this cannot be uploaded. Reduce the size by removing unused packages, splitting the solution into smaller solutions, or trimming large binary assets.`;
371
+ this.logger.error(`Built solution size ${currentMb} MB exceeds maximum allowed ${maxMb} MB.`);
372
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, message);
373
+ }
374
+ async getTotalDirectorySize(dirPath) {
375
+ let total = 0;
376
+ const stack = [
377
+ dirPath
378
+ ];
379
+ let current = stack.pop();
380
+ while (current !== undefined) {
381
+ const entries = await this.fileSystem.readdir(current);
382
+ for (const entry of entries) {
383
+ const fullPath = Path.join(current, entry);
384
+ const stats = await this.fileSystem.stat(fullPath);
385
+ if (stats) {
386
+ if (stats.isDirectory())
387
+ stack.push(fullPath);
388
+ else if (stats.isFile())
389
+ total += stats.size;
390
+ }
391
+ }
392
+ current = stack.pop();
393
+ }
394
+ return total;
395
+ }
396
+ async restoreAsync(options, cancellationToken) {
397
+ this.logger.info("Restore starting.");
398
+ this.inputPath = Path.dirname(options.solutionFilePath);
399
+ try {
400
+ throwIfCancelled(cancellationToken);
401
+ const existingResources = await this.readFromDirectory(KNOWN_ARCHIVE_FOLDERS.resources, cancellationToken);
402
+ this.logger.info(`Read ${existingResources.length} existing resources from ${KNOWN_ARCHIVE_FOLDERS.resources} directory.`);
403
+ if (existingResources.length === 0) {
404
+ this.logger.error("Solution definition empty or not found.");
405
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, "Solution definition empty or not found.");
406
+ }
407
+ const filteredResources = this.filterResources(existingResources, {
408
+ configuration: options.configuration,
409
+ projectsToBuild: options.projectsToBuild
410
+ });
411
+ const files = this.extractFilesFromResources(filteredResources);
412
+ const filesToDownload = files.filter((f) => f.url != null);
413
+ if (filesToDownload.length === 0) {
414
+ this.logger.info("No files to download.");
415
+ this.logger.info("Restore finished.");
416
+ return ToolResult.success();
417
+ }
418
+ const outputPath = options.outputPath ?? "";
419
+ const downloadTasks = [];
420
+ const semaphore = new Semaphore(MAX_DOWNLOAD_CONCURRENCY);
421
+ for (const file of filesToDownload) {
422
+ throwIfCancelled(cancellationToken);
423
+ this.logger.info(`Downloading file ${file.name} kind ${file.kind} from service url ${file.url}...`);
424
+ const resource = this.findResourceForFile(filteredResources, file);
425
+ if (!resource) {
426
+ this.logger.warn(`File with name '${file.name}', kind '${file.kind}', key '${file.key}' not referenced by any resource.`);
427
+ continue;
428
+ }
429
+ const filePath = Path.join(outputPath, KNOWN_ARCHIVE_FOLDERS.files, file.key, file.name);
430
+ if (await this.fileSystem.exists(filePath)) {
431
+ this.logger.info(`File ${file.name} already exists at ${filePath}, skipping download.`);
432
+ continue;
433
+ }
434
+ const dirPath = Path.dirname(filePath);
435
+ await this.fileSystem.mkdir(dirPath);
436
+ const serviceName = resource.apiVersion ?? "unknown";
437
+ downloadTasks.push(this.downloadFileWithSemaphore(semaphore, file, filePath, serviceName, options, cancellationToken));
438
+ }
439
+ if (downloadTasks.length === 0) {
440
+ this.logger.info("No files to download.");
441
+ this.logger.info("Restore finished.");
442
+ return ToolResult.success();
443
+ }
444
+ const results = await Promise.all(downloadTasks);
445
+ const failures = results.filter((r) => !r.isSuccess && r.failure != null).map((r) => r.failure);
446
+ if (failures.length > 0) {
447
+ for (const failure of failures)
448
+ this.logger.error(`Download failed for file ${failure.fileKey} from service ${failure.service} at ${failure.externalUrl}. Reason: ${failure.reason}. ${failure.errorMessage ?? ""}`);
449
+ const message = buildFailureMessage(failures);
450
+ this.logger.error(message);
451
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, message);
452
+ }
453
+ this.logger.info("Restore finished.");
454
+ return ToolResult.success();
455
+ } catch (error) {
456
+ const message = error instanceof Error ? error.message : String(error);
457
+ this.logger.error(`Restore failed: ${message}`);
458
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, `Restore failed: ${message}`);
459
+ }
460
+ }
461
+ async validateAsync(options, cancellationToken) {
462
+ this.logger.info("Validate starting.");
463
+ if (options.solutionFilePath === undefined)
464
+ throw new Error("Solution file path is undefined.");
465
+ this.inputPath = Path.dirname(options.solutionFilePath);
466
+ try {
467
+ throwIfCancelled(cancellationToken);
468
+ const packageVersion = options.packageVersion;
469
+ if (packageVersion !== undefined && !this.isValidSemanticVersion(packageVersion)) {
470
+ this.logger.error(`Invalid package version ${packageVersion}`);
471
+ return ToolResult.error("VALIDATION_ERROR", `Invalid package version: ${packageVersion}`);
472
+ }
473
+ this.logger.info("Validate finished.");
474
+ return ToolResult.success();
475
+ } catch (error) {
476
+ const message = error instanceof Error ? error.message : String(error);
477
+ this.logger.error(`Validation failed: ${message}`);
478
+ return ToolResult.error("INTERNAL_ERROR" /* InternalError */, `Validation failed: ${message}`);
479
+ }
480
+ }
481
+ async readFromDirectory(folderName, cancellationToken) {
482
+ const basePath = this.inputPath;
483
+ const folderPath = folderName ? Path.join(basePath, folderName) : basePath;
484
+ const resources = [];
485
+ if (!await this.fileSystem.exists(folderPath))
486
+ return resources;
487
+ throwIfCancelled(cancellationToken);
488
+ const allFiles = await this.readFilesRecursively(folderPath, cancellationToken);
489
+ const jsonFiles = allFiles.filter((f) => f.endsWith(".json"));
490
+ this.logger.info(`Found ${jsonFiles.length} resource JSON files in ${folderName ?? basePath} directory.`);
491
+ const failedFiles = [];
492
+ for (const fileRelativeToFolder of jsonFiles) {
493
+ throwIfCancelled(cancellationToken);
494
+ const normalizedFileRelative = fileRelativeToFolder.replace(/\\/g, "/");
495
+ const relativeToBasePath = folderName ? `${folderName}/${normalizedFileRelative}` : normalizedFileRelative;
496
+ try {
497
+ const fullFilePath = Path.join(basePath, relativeToBasePath);
498
+ const content = await this.fileSystem.readFile(fullFilePath);
499
+ if (!content) {
500
+ this.logger.warn(`Failed to read resource file: ${relativeToBasePath}`);
501
+ continue;
502
+ }
503
+ const jsonContent = new TextDecoder().decode(content);
504
+ const wrapper = JSON.parse(jsonContent);
505
+ if (wrapper?.resource) {
506
+ const rd = wrapper.resource;
507
+ const normalizedPath = fileRelativeToFolder.replace(/\\/g, "/");
508
+ const segments = normalizedPath.split("/").filter((s) => s.length > 0);
509
+ if (segments.length >= 2) {
510
+ const hasType = rd.type != null && rd.type.trim() !== "";
511
+ const folderSegmentCount = hasType ? segments.length - 3 : segments.length - 2;
512
+ if (folderSegmentCount < 1)
513
+ rd.folders = [
514
+ {
515
+ fullyQualifiedName: PACKAGE_DEFAULTS.rootFolderName
516
+ }
517
+ ];
518
+ else {
519
+ const segmentsToUse = segments.slice(0, folderSegmentCount);
520
+ const folderFqn = segmentsToUse.join("/");
521
+ rd.folders = [
522
+ {
523
+ fullyQualifiedName: folderFqn
524
+ }
525
+ ];
526
+ }
527
+ } else
528
+ rd.folders = [
529
+ {
530
+ fullyQualifiedName: PACKAGE_DEFAULTS.rootFolderName
531
+ }
532
+ ];
533
+ resources.push(rd);
534
+ this.logger.info(`Read resource: ${rd.name} kind: ${rd.kind} from ${relativeToBasePath}`);
535
+ }
536
+ } catch (ex) {
537
+ const message = ex instanceof Error ? ex.message : String(ex);
538
+ this.logger.error(`Failed to read resource file ${relativeToBasePath}: ${message}`);
539
+ failedFiles.push(relativeToBasePath);
540
+ }
541
+ }
542
+ if (failedFiles.length > 0)
543
+ throw new Error(`Failed to read resource files: ${failedFiles.join(", ")}`);
544
+ return resources;
545
+ }
546
+ async readFilesRecursively(basePath, cancellationToken) {
547
+ const results = [];
548
+ const processDirectory = async (currentPath, relativePath) => {
549
+ throwIfCancelled(cancellationToken);
550
+ const entries = await this.fileSystem.readdir(currentPath);
551
+ for (const entry of entries) {
552
+ const fullPath = Path.join(currentPath, entry);
553
+ const relPath = relativePath ? `${relativePath}/${entry}` : entry;
554
+ const stats = await this.fileSystem.stat(fullPath);
555
+ if (stats?.isDirectory())
556
+ await processDirectory(fullPath, relPath);
557
+ else if (stats?.isFile())
558
+ results.push(relPath);
559
+ }
560
+ };
561
+ await processDirectory(basePath, "");
562
+ return results;
563
+ }
564
+ filterResources(resources, options) {
565
+ const { projectsToBuild, configuration } = options;
566
+ if (!resources)
567
+ return [];
568
+ if (configuration !== "Debug" /* Debug */)
569
+ return resources;
570
+ if (!projectsToBuild || projectsToBuild.length === 0)
571
+ return resources;
572
+ const projectsToBuildSet = new Set(projectsToBuild);
573
+ return resources.filter((resource) => {
574
+ if (!isArtefactResource(resource))
575
+ return true;
576
+ const projectKey = resource.projectKey;
577
+ if (!projectKey || !projectsToBuildSet.has(projectKey)) {
578
+ this.logger.info(`Artefact resource skipped: ${resource.key}`);
579
+ return false;
580
+ }
581
+ return true;
582
+ });
583
+ }
584
+ async writeResources(resources, options, cancellationToken) {
585
+ for (const resource of resources) {
586
+ throwIfCancelled(cancellationToken);
587
+ const resourcePath = this.buildResourceRelativePath(resource);
588
+ const fullPath = Path.join(options.outputPath, resourcePath);
589
+ const dirPath = Path.dirname(fullPath);
590
+ await this.fileSystem.mkdir(dirPath);
591
+ const wrapper = {
592
+ docVersion: PACKAGE_DEFAULTS.currentDocVersion,
593
+ resource
594
+ };
595
+ await this.fileSystem.writeFile(fullPath, serializeJson(wrapper));
596
+ this.logger.info(`Writing resource file for resource ${resource.key}`);
597
+ }
598
+ }
599
+ buildResourceRelativePath(resource) {
600
+ const safeName = this.sanitizeFileName(resource.name);
601
+ const folderFqn = resource.folders[0]?.fullyQualifiedName ?? "";
602
+ const parts = [
603
+ KNOWN_ARCHIVE_FOLDERS.resources
604
+ ];
605
+ const folderSegments = folderFqn.split("/").filter((s) => s.length > 0);
606
+ if (folderSegments.length > 0)
607
+ parts.push(...folderSegments);
608
+ else
609
+ parts.push(PACKAGE_DEFAULTS.rootFolderName);
610
+ parts.push(resource.kind);
611
+ if (resource.type && resource.type.trim())
612
+ parts.push(resource.type);
613
+ parts.push(`${safeName}.json`);
614
+ return Path.join(...parts);
615
+ }
616
+ sanitizeFileName(name) {
617
+ return name.replace(INVALID_FILE_NAME_CHARS, "_");
618
+ }
619
+ isValidSemanticVersion(version) {
620
+ const semverRegex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
621
+ return semverRegex.test(version);
622
+ }
623
+ async writePackageFiles(options, tokenData, cancellationToken) {
624
+ throwIfCancelled(cancellationToken);
625
+ const packageName = options.package.id;
626
+ if (!packageName)
627
+ throw new Error("Package name not found");
628
+ const packageVersion = options.package.version ?? PACKAGE_DEFAULTS.defaultPackageVersion;
629
+ const uipxContentBuffer = await this.fileSystem.readFile(options.solutionFilePath);
630
+ if (!uipxContentBuffer)
631
+ throw new Error(`Failed to read solution file: ${options.solutionFilePath}`);
632
+ const uipxContent = new TextDecoder().decode(uipxContentBuffer);
633
+ const uipxData = JSON.parse(uipxContent);
634
+ if (!uipxData.SolutionId)
635
+ throw new Error(`SolutionId not found in solution file: ${options.solutionFilePath}`);
636
+ const solutionId = uipxData.SolutionId;
637
+ this.logger.info(`Extracted SolutionId from .uipx file: ${solutionId}`);
638
+ let authorName = options.package.author;
639
+ if (!authorName) {
640
+ const nameParts = [
641
+ tokenData.firstName,
642
+ tokenData.lastName
643
+ ].filter((s) => s != null && s.trim() !== "");
644
+ authorName = nameParts.length > 0 ? nameParts.join(" ").trim() : PACKAGE_DEFAULTS.defaultAuthorName;
645
+ }
646
+ const packageVersionKey = options.publishId ?? crypto.randomUUID();
647
+ const metadata = {
648
+ authorEmail: tokenData.email,
649
+ authorName,
650
+ description: options.package.description,
651
+ releaseNotes: options.package.releaseNotes,
652
+ packageName,
653
+ packageVersion,
654
+ projectKey: solutionId,
655
+ packageVersionKey,
656
+ origin: "Studio",
657
+ configuration: options.configuration
658
+ };
659
+ this.logger.info(`Creating solution package with name '${metadata.packageName}' and version '${metadata.packageVersion}'.`);
660
+ await this.writePackageInfo(options.outputPath);
661
+ throwIfCancelled(cancellationToken);
662
+ await this.writeMetadata(options.outputPath, metadata);
663
+ }
664
+ async writePackageInfo(outputPath) {
665
+ const packageInfo = {
666
+ version: PACKAGE_DEFAULTS.currentVersion,
667
+ type: PACKAGE_DEFAULTS.unifiedBuildPackageType
668
+ };
669
+ const packageInfoPath = Path.join(outputPath, KNOWN_ARCHIVE_FILE_NAMES.packageInfoJsonFileName);
670
+ await this.fileSystem.writeFile(packageInfoPath, serializeJson(packageInfo));
671
+ }
672
+ async writeMetadata(outputPath, metadata) {
673
+ const metadataResource = {
674
+ apiVersion: "solutions.uipath.com/v1",
675
+ kind: "Metadata",
676
+ spec: metadata
677
+ };
678
+ const metadataPath = Path.join(outputPath, KNOWN_ARCHIVE_FILE_NAMES.metadataJsonFileName);
679
+ await this.fileSystem.writeFile(metadataPath, serializeJson(metadataResource));
680
+ }
681
+ async downloadFile(file, filePath, serviceName, options, cancellationToken) {
682
+ const maxRetryAttempts = RESILIENCE_DEFAULTS.maxRetryAttempts;
683
+ const retryIntervalMs = RESILIENCE_DEFAULTS.retryIntervalMs;
684
+ const accessToken = options.connection?.accessToken;
685
+ const externalUrl = file.url;
686
+ if (!externalUrl)
687
+ throw new Error("File URL is required for download");
688
+ let currentUrl = externalUrl;
689
+ let redirectCount = 0;
690
+ const createFailure = (reason, errorMessage) => ({
691
+ isSuccess: false,
692
+ failure: {
693
+ fileKey: file.key,
694
+ service: serviceName,
695
+ externalUrl,
696
+ reason,
697
+ errorMessage: truncateMessage(errorMessage, MAX_SERVER_MESSAGE_LENGTH)
698
+ }
699
+ });
700
+ try {
701
+ while (redirectCount < RESILIENCE_DEFAULTS.maxRedirectRetries) {
702
+ const response = await this.fetchWithRetry(currentUrl, accessToken, maxRetryAttempts, retryIntervalMs, file.name, cancellationToken);
703
+ if (isRedirectStatusCode(response.status)) {
704
+ const location = response.headers.get("location");
705
+ if (!location)
706
+ return createFailure("TooManyRedirects", "Redirect response without location header");
707
+ currentUrl = location;
708
+ redirectCount++;
709
+ this.logger.info(`Following redirect for file ${file.name} to ${location}`);
710
+ continue;
711
+ }
712
+ if (isClientError(response.status)) {
713
+ const serverMessage = await this.readResponseTextSafe(response);
714
+ if (accessToken) {
715
+ this.logger.info(`Retrying download of file ${file.name} without access token`);
716
+ const retryResponse = await this.fetchWithRetry(currentUrl, undefined, maxRetryAttempts, retryIntervalMs, file.name, cancellationToken);
717
+ if (retryResponse.ok) {
718
+ const buffer2 = await retryResponse.arrayBuffer();
719
+ await this.fileSystem.writeFile(filePath, Buffer.from(buffer2));
720
+ this.logger.info(`File ${file.name} written to ${filePath}.`);
721
+ return {
722
+ isSuccess: true
723
+ };
724
+ }
725
+ const retryServerMessage = await this.readResponseTextSafe(retryResponse);
726
+ return createFailure(mapHttpStatusCodeToReason(retryResponse.status), retryServerMessage ?? `HTTP ${retryResponse.status}`);
727
+ }
728
+ return createFailure(mapHttpStatusCodeToReason(response.status), serverMessage ?? `HTTP ${response.status}`);
729
+ }
730
+ if (!response.ok) {
731
+ const serverMessage = await this.readResponseTextSafe(response);
732
+ return createFailure(mapHttpStatusCodeToReason(response.status), serverMessage ?? `HTTP ${response.status}: ${response.statusText}`);
733
+ }
734
+ const buffer = await response.arrayBuffer();
735
+ await this.fileSystem.writeFile(filePath, Buffer.from(buffer));
736
+ this.logger.info(`File ${file.name} written to ${filePath}.`);
737
+ return {
738
+ isSuccess: true
739
+ };
740
+ }
741
+ return createFailure("TooManyRedirects", "Too many redirects");
742
+ } catch (error) {
743
+ if (cancellationToken?.aborted)
744
+ return createFailure("Cancelled", "Operation was cancelled");
745
+ const message = error instanceof Error ? error.message : String(error);
746
+ if (message.toLowerCase().includes("timeout") || message.toLowerCase().includes("timed out"))
747
+ return createFailure("Timeout", message);
748
+ if (message.toLowerCase().includes("network") || message.toLowerCase().includes("econnrefused") || message.toLowerCase().includes("enotfound"))
749
+ return createFailure("ConnectionError", message);
750
+ return createFailure("Unknown", message);
751
+ }
752
+ }
753
+ async readResponseTextSafe(response) {
754
+ try {
755
+ const text = await response.text();
756
+ return truncateMessage(text, MAX_SERVER_MESSAGE_LENGTH);
757
+ } catch {
758
+ return;
759
+ }
760
+ }
761
+ extractFilesFromResources(resources) {
762
+ const files = [];
763
+ for (const resource of resources)
764
+ if (resource.files && resource.files.length !== 0)
765
+ for (const file of resource.files)
766
+ files.push({
767
+ name: file.name,
768
+ kind: file.kind,
769
+ key: file.key ?? resource.key ?? "",
770
+ url: file.url
771
+ });
772
+ return files;
773
+ }
774
+ findResourceForFile(resources, file) {
775
+ return resources.find((resource) => {
776
+ if (!resource.files || resource.files.length === 0)
777
+ return false;
778
+ return resource.files.some((rf) => rf.name === file.name && rf.kind === file.kind);
779
+ });
780
+ }
781
+ async downloadFileWithSemaphore(semaphore, file, filePath, serviceName, options, cancellationToken) {
782
+ await semaphore.acquire();
783
+ try {
784
+ return await this.downloadFile(file, filePath, serviceName, options, cancellationToken);
785
+ } finally {
786
+ semaphore.release();
787
+ }
788
+ }
789
+ async fetchWithRetry(url, accessToken, maxRetryAttempts, retryIntervalMs, fileName, cancellationToken) {
790
+ let lastError;
791
+ for (let attempt = 1;attempt <= maxRetryAttempts + 1; attempt++)
792
+ try {
793
+ const response = await fetch(url, {
794
+ signal: cancellationToken,
795
+ headers: accessToken ? {
796
+ Authorization: `Bearer ${accessToken}`
797
+ } : undefined,
798
+ redirect: "manual"
799
+ });
800
+ if (isRetriableStatusCode(response.status) && attempt <= maxRetryAttempts) {
801
+ const delayMs = retryIntervalMs * attempt;
802
+ this.logger.warn(`Retriable error (HTTP ${response.status}) downloading file ${fileName}, attempt ${attempt}/${maxRetryAttempts}. Retrying in ${delayMs}ms...`);
803
+ await delay(delayMs, cancellationToken);
804
+ continue;
805
+ }
806
+ return response;
807
+ } catch (error) {
808
+ lastError = error instanceof Error ? error : new Error(String(error));
809
+ if (attempt <= maxRetryAttempts) {
810
+ const delayMs = retryIntervalMs * attempt;
811
+ this.logger.warn(`Network error downloading file ${fileName}, attempt ${attempt}/${maxRetryAttempts}: ${lastError.message}. Retrying in ${delayMs}ms...`);
812
+ await delay(delayMs, cancellationToken);
813
+ continue;
814
+ }
815
+ }
816
+ throw lastError ?? new Error(`Failed to download file ${fileName} after ${maxRetryAttempts} retries`);
817
+ }
818
+ constructor(fileSystem, logger) {
819
+ super(fileSystem, logger), _define_property(this, "inputPath", "");
820
+ }
821
+ }
822
+
823
+ class ResourceBuilderToolFactory {
824
+ async createAsync(logger, fileSystem) {
825
+ return new ResourceBuilderTool(fileSystem, logger);
826
+ }
827
+ }
828
+
829
+ // src/packager-tool.ts
830
+ function registerPackagerFactories() {
831
+ toolsFactoryRepository.registerSolutionToolFactory(new ResourceBuilderToolFactory);
832
+ toolsFactoryRepository.registerProjectToolFactory(new ConnectorToolFactory);
833
+ }
834
+
835
+ export { registerPackagerFactories };
836
+
837
+ //# debugId=D9EA794DD6EA909B64756E2164756E21