@uipath/packager-tool-workflowcompiler-browser 0.0.29 → 1.196.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/dist/i18n/locales/en.d.ts +8 -2
- package/dist/index.js +251 -128
- package/dist/pack-result-processor.d.ts +2 -2
- package/dist/project-bundle-executor.d.ts +25 -8
- package/dist/workflow-compiler-tool.d.ts +4 -3
- package/package.json +12 -29
- package/src/i18n/locales/de.json +6 -4
- package/src/i18n/locales/en.ts +16 -4
- package/src/i18n/locales/es-MX.json +6 -4
- package/src/i18n/locales/es.json +6 -4
- package/src/i18n/locales/fr.json +6 -4
- package/src/i18n/locales/ja.json +6 -4
- package/src/i18n/locales/ko.json +6 -4
- package/src/i18n/locales/pt-BR.json +6 -4
- package/src/i18n/locales/pt.json +6 -4
- package/src/i18n/locales/ro.json +6 -4
- package/src/i18n/locales/ru.json +6 -4
- package/src/i18n/locales/tr.json +6 -4
- package/src/i18n/locales/zh-CN.json +6 -4
- package/src/i18n/locales/zh-TW.json +6 -4
- package/src/i18n/locales/zu.json +6 -4
- package/src/pack-result-processor.ts +4 -6
- package/src/packager-hub-connection.ts +15 -40
- package/src/project-bundle-executor.ts +270 -40
- package/src/workflow-compiler-tool.ts +15 -9
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type IFileSystem,
|
|
4
4
|
type IProjectPackOptions,
|
|
5
5
|
type IProjectToolFactory,
|
|
6
|
+
type IProjectValidateOptions,
|
|
6
7
|
type IToolLogger,
|
|
7
8
|
type ProjectOperationContext,
|
|
8
9
|
ToolResult,
|
|
@@ -18,12 +19,27 @@ import {
|
|
|
18
19
|
|
|
19
20
|
type ResolveCallback = (result: ToolResult) => void;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
export enum BundleOperation {
|
|
23
|
+
Pack = "Pack",
|
|
24
|
+
Validate = "Validate",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface PackEntry {
|
|
28
|
+
operation: BundleOperation.Pack;
|
|
22
29
|
options: IProjectPackOptions;
|
|
23
30
|
resolve: ResolveCallback;
|
|
24
31
|
}
|
|
25
32
|
|
|
33
|
+
interface ValidateEntry {
|
|
34
|
+
operation: BundleOperation.Validate;
|
|
35
|
+
options: IProjectValidateOptions;
|
|
36
|
+
resolve: ResolveCallback;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type ProjectEntry = PackEntry | ValidateEntry;
|
|
40
|
+
|
|
26
41
|
interface BundleSession {
|
|
42
|
+
operation: BundleOperation;
|
|
27
43
|
expectedCount: number;
|
|
28
44
|
projects: Map<string, ProjectEntry>;
|
|
29
45
|
timeout?: ReturnType<typeof setTimeout>;
|
|
@@ -34,16 +50,40 @@ export interface IProjectBundleExecutor {
|
|
|
34
50
|
options: IProjectPackOptions,
|
|
35
51
|
context: ProjectOperationContext,
|
|
36
52
|
): Promise<ToolResult>;
|
|
53
|
+
|
|
54
|
+
validateAsync(
|
|
55
|
+
options: IProjectValidateOptions,
|
|
56
|
+
context: ProjectOperationContext,
|
|
57
|
+
): Promise<ToolResult>;
|
|
37
58
|
}
|
|
38
59
|
|
|
39
60
|
/**
|
|
40
|
-
* Coordinates
|
|
41
|
-
* Waits until all compatible projects have submitted their
|
|
42
|
-
* then executes a single bundled operation and resolves all pending promises.
|
|
61
|
+
* Coordinates pack or validate of multiple projects within a single operation context.
|
|
62
|
+
* Waits until all compatible projects have submitted their options,
|
|
63
|
+
* then executes a single bundled remote-agent operation and resolves all pending promises.
|
|
64
|
+
*/
|
|
65
|
+
/**
|
|
66
|
+
* Shape of the `POST /odata/Attachments` response. Orchestrator returns
|
|
67
|
+
* PascalCase (`Id`, `BlobFileAccess.Uri`); the camelCase fallbacks mirror the
|
|
68
|
+
* defensive reads in `@uipath/orchestrator-sdk`'s `uploadJobAttachment`.
|
|
43
69
|
*/
|
|
70
|
+
interface AttachmentResponse {
|
|
71
|
+
Id?: string;
|
|
72
|
+
id?: string;
|
|
73
|
+
BlobFileAccess?: { Uri: string };
|
|
74
|
+
blobFileAccess?: { Uri: string };
|
|
75
|
+
}
|
|
76
|
+
|
|
44
77
|
export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
45
78
|
static readonly SESSION_TIMEOUT_MS = 1_800_000;
|
|
46
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Maximum length (in characters) of the inline `inputArguments` payload
|
|
82
|
+
* accepted by the serverless jobs endpoint. Beyond this the arguments must
|
|
83
|
+
* be uploaded as a file attachment and referenced via `inputFile`.
|
|
84
|
+
*/
|
|
85
|
+
static readonly MAX_INLINE_INPUT_ARGUMENTS_LENGTH = 10_000;
|
|
86
|
+
|
|
47
87
|
private readonly sessions = new Map<string, BundleSession>();
|
|
48
88
|
private readonly pendingSessionCreations = new Map<
|
|
49
89
|
string,
|
|
@@ -59,25 +99,59 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
59
99
|
options: IProjectPackOptions,
|
|
60
100
|
context: ProjectOperationContext,
|
|
61
101
|
): Promise<ToolResult> {
|
|
62
|
-
|
|
102
|
+
return this.enqueueAsync(context, {
|
|
103
|
+
operation: BundleOperation.Pack,
|
|
104
|
+
options,
|
|
105
|
+
resolve: () => {},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async validateAsync(
|
|
110
|
+
options: IProjectValidateOptions,
|
|
111
|
+
context: ProjectOperationContext,
|
|
112
|
+
): Promise<ToolResult> {
|
|
113
|
+
return this.enqueueAsync(context, {
|
|
114
|
+
operation: BundleOperation.Validate,
|
|
115
|
+
options,
|
|
116
|
+
resolve: () => {},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private async enqueueAsync(
|
|
121
|
+
context: ProjectOperationContext,
|
|
122
|
+
entry: ProjectEntry,
|
|
123
|
+
): Promise<ToolResult> {
|
|
124
|
+
const projectPath = entry.options.projectPath;
|
|
63
125
|
context.logger?.info(
|
|
64
|
-
`[BundleExecutor]
|
|
126
|
+
`[BundleExecutor] ${entry.operation}Async called for project: ${projectPath}`,
|
|
65
127
|
);
|
|
66
|
-
const session = await this.getSessionAsync(context);
|
|
128
|
+
const session = await this.getSessionAsync(context, entry.operation);
|
|
67
129
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
130
|
+
if (session.operation !== entry.operation) {
|
|
131
|
+
return ToolResult.error(
|
|
132
|
+
"BundleOperationMismatch",
|
|
133
|
+
translate.t(
|
|
134
|
+
"toolWorkflowCompilerBrowser.errors.bundleOperationMismatch",
|
|
135
|
+
{
|
|
136
|
+
sessionOperation: session.operation,
|
|
137
|
+
entryOperation: entry.operation,
|
|
138
|
+
},
|
|
139
|
+
),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const promise = new Promise<ToolResult>((resolve) => {
|
|
144
|
+
entry.resolve = resolve;
|
|
71
145
|
});
|
|
72
|
-
session.projects.set(projectPath,
|
|
146
|
+
session.projects.set(projectPath, entry);
|
|
73
147
|
const allReceived = session.projects.size === session.expectedCount;
|
|
74
148
|
context.logger?.info(
|
|
75
|
-
`[BundleExecutor] session: ${session.projects.size}/${session.expectedCount} projects received. allReceived=${allReceived}`,
|
|
149
|
+
`[BundleExecutor] session (${session.operation}): ${session.projects.size}/${session.expectedCount} projects received. allReceived=${allReceived}`,
|
|
76
150
|
);
|
|
77
151
|
|
|
78
152
|
if (allReceived) {
|
|
79
153
|
clearTimeout(session.timeout);
|
|
80
|
-
await this.
|
|
154
|
+
await this.runAgentAsync(session, context);
|
|
81
155
|
this.sessions.delete(context.id);
|
|
82
156
|
}
|
|
83
157
|
|
|
@@ -86,6 +160,7 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
86
160
|
|
|
87
161
|
private getSessionAsync(
|
|
88
162
|
context: ProjectOperationContext,
|
|
163
|
+
operation: BundleOperation,
|
|
89
164
|
): Promise<BundleSession> {
|
|
90
165
|
const existing = this.sessions.get(context.id);
|
|
91
166
|
if (existing) {
|
|
@@ -94,7 +169,7 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
94
169
|
|
|
95
170
|
let pending = this.pendingSessionCreations.get(context.id);
|
|
96
171
|
if (!pending) {
|
|
97
|
-
pending = this.createSessionAsync(context);
|
|
172
|
+
pending = this.createSessionAsync(context, operation);
|
|
98
173
|
this.pendingSessionCreations.set(context.id, pending);
|
|
99
174
|
}
|
|
100
175
|
return pending;
|
|
@@ -102,9 +177,11 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
102
177
|
|
|
103
178
|
private async createSessionAsync(
|
|
104
179
|
context: ProjectOperationContext,
|
|
180
|
+
operation: BundleOperation,
|
|
105
181
|
): Promise<BundleSession> {
|
|
106
182
|
const expectedCount = this.countCompatibleProjects(context);
|
|
107
183
|
const session: BundleSession = {
|
|
184
|
+
operation,
|
|
108
185
|
expectedCount,
|
|
109
186
|
projects: new Map(),
|
|
110
187
|
};
|
|
@@ -135,15 +212,16 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
135
212
|
return session;
|
|
136
213
|
}
|
|
137
214
|
|
|
138
|
-
private async
|
|
215
|
+
private async runAgentAsync(
|
|
139
216
|
session: BundleSession,
|
|
140
217
|
context: ProjectOperationContext,
|
|
141
218
|
): Promise<void> {
|
|
142
219
|
const projectPaths = [...session.projects.keys()];
|
|
143
220
|
context.logger?.info(
|
|
144
221
|
translate.t(
|
|
145
|
-
"toolWorkflowCompilerBrowser.info.
|
|
222
|
+
"toolWorkflowCompilerBrowser.info.startingRemoteAgent",
|
|
146
223
|
{
|
|
224
|
+
operation: session.operation,
|
|
147
225
|
count: session.expectedCount,
|
|
148
226
|
paths: projectPaths.join(", "),
|
|
149
227
|
},
|
|
@@ -205,16 +283,16 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
205
283
|
context.logger?.info(
|
|
206
284
|
`[BundleExecutor] Got result: errorCode=${result.errorCode}, status=${result.status}, message=${result.message}, bucketId=${result.bucketId}`,
|
|
207
285
|
);
|
|
208
|
-
await this.
|
|
286
|
+
await this.handleAgentResultAsync(result, session, context);
|
|
209
287
|
} catch (error) {
|
|
210
288
|
const message =
|
|
211
289
|
error instanceof Error ? error.message : String(error);
|
|
212
290
|
context.logger?.error(
|
|
213
|
-
`[BundleExecutor]
|
|
291
|
+
`[BundleExecutor] runAgentAsync caught error: ${message}`,
|
|
214
292
|
);
|
|
215
293
|
this.resolveAll(
|
|
216
294
|
session,
|
|
217
|
-
ToolResult.error(
|
|
295
|
+
ToolResult.error(`${session.operation}AgentError`, message),
|
|
218
296
|
);
|
|
219
297
|
} finally {
|
|
220
298
|
await hubConnection.disconnectAsync();
|
|
@@ -251,7 +329,7 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
251
329
|
}
|
|
252
330
|
}
|
|
253
331
|
|
|
254
|
-
private async
|
|
332
|
+
private async handleAgentResultAsync(
|
|
255
333
|
result: PackAgentResult,
|
|
256
334
|
session: BundleSession,
|
|
257
335
|
context: ProjectOperationContext,
|
|
@@ -263,11 +341,12 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
263
341
|
this.resolveAll(
|
|
264
342
|
session,
|
|
265
343
|
ToolResult.error(
|
|
266
|
-
|
|
344
|
+
`${session.operation}AgentError`,
|
|
267
345
|
result.message ??
|
|
268
346
|
translate.t(
|
|
269
|
-
"toolWorkflowCompilerBrowser.errors.
|
|
347
|
+
"toolWorkflowCompilerBrowser.errors.agentFailed",
|
|
270
348
|
{
|
|
349
|
+
operation: session.operation,
|
|
271
350
|
status: result.status,
|
|
272
351
|
errorCode: result.errorCode,
|
|
273
352
|
},
|
|
@@ -277,6 +356,19 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
277
356
|
return;
|
|
278
357
|
}
|
|
279
358
|
|
|
359
|
+
if (session.operation === BundleOperation.Pack) {
|
|
360
|
+
await this.handlePackBucketAsync(result, session, context);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
this.resolveAll(session, ToolResult.success());
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
private async handlePackBucketAsync(
|
|
368
|
+
result: PackAgentResult,
|
|
369
|
+
session: BundleSession,
|
|
370
|
+
context: ProjectOperationContext,
|
|
371
|
+
): Promise<void> {
|
|
280
372
|
if (result.bucketId == null) {
|
|
281
373
|
this.resolveAll(
|
|
282
374
|
session,
|
|
@@ -290,13 +382,20 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
290
382
|
return;
|
|
291
383
|
}
|
|
292
384
|
|
|
385
|
+
const packEntries = new Map<string, { options: IProjectPackOptions }>();
|
|
386
|
+
for (const [projectPath, entry] of session.projects) {
|
|
387
|
+
if (entry.operation === BundleOperation.Pack) {
|
|
388
|
+
packEntries.set(projectPath, { options: entry.options });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
293
392
|
const resultProcessor = new PackResultProcessor(
|
|
294
393
|
this.fileSystem,
|
|
295
394
|
context.logger,
|
|
296
395
|
);
|
|
297
396
|
const perProjectResults = await resultProcessor.processAsync(
|
|
298
397
|
result.bucketId,
|
|
299
|
-
|
|
398
|
+
packEntries,
|
|
300
399
|
context,
|
|
301
400
|
);
|
|
302
401
|
for (const [projectPath, entry] of session.projects) {
|
|
@@ -321,56 +420,107 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
321
420
|
): Promise<void> {
|
|
322
421
|
const relativeBase = toRelativeUrl(connection.cloudUrl!);
|
|
323
422
|
const url = `${relativeBase}/orchestrator_/api/serverless/jobs`;
|
|
423
|
+
//const url = `${relativeBase}/orchestrator_/api/RobotDebug/BeginSession`;
|
|
424
|
+
|
|
324
425
|
context.logger?.info(`[BundleExecutor] BeginSession URL: ${url}`);
|
|
325
426
|
|
|
326
|
-
// Use the first entry for shared fields (package info, options)
|
|
327
427
|
const firstEntry = session.projects.values().next().value!;
|
|
328
|
-
const pkg = firstEntry.options.package;
|
|
329
428
|
const opts = firstEntry.options;
|
|
330
429
|
|
|
331
|
-
// Build RpaProjects from all projects in the session
|
|
332
430
|
const rpaProjects = [...session.projects.entries()].map(
|
|
333
431
|
([projectPath, entry]) => {
|
|
334
|
-
const project = context.
|
|
432
|
+
const project = context.projects.find(
|
|
335
433
|
(p) => p.ProjectPath === projectPath,
|
|
336
434
|
);
|
|
337
435
|
return {
|
|
338
436
|
RelativePath: project?.ProjectRelativePath ?? "",
|
|
339
437
|
DesignId: project?.Id ?? "",
|
|
340
|
-
|
|
438
|
+
ProjectStorageId:
|
|
439
|
+
entry.operation === BundleOperation.Pack
|
|
440
|
+
? (entry.options.projectStorageId ?? "")
|
|
441
|
+
: "",
|
|
442
|
+
PackageId:
|
|
443
|
+
entry.operation === BundleOperation.Pack
|
|
444
|
+
? entry.options.package.id
|
|
445
|
+
: "",
|
|
341
446
|
};
|
|
342
447
|
},
|
|
343
448
|
);
|
|
344
449
|
|
|
345
|
-
const executorInfo =
|
|
346
|
-
Command:
|
|
450
|
+
const executorInfo: Record<string, unknown> = {
|
|
451
|
+
Command: session.operation,
|
|
347
452
|
SupportedProtocolVersions: ["2.0"],
|
|
348
|
-
ProjectId: "",
|
|
349
453
|
DownloadUrl: context.downloadUrl ?? "",
|
|
350
454
|
SessionId: sessionId,
|
|
351
455
|
ProfileKey: "StudioWeb",
|
|
352
456
|
LicenseType: "Development",
|
|
353
457
|
LogLevel: opts.logLevel ?? "Warning",
|
|
354
|
-
Name: pkg.id,
|
|
355
|
-
Configuration: context.configuration,
|
|
356
458
|
Culture: "en-US",
|
|
357
|
-
|
|
358
|
-
Author: pkg.author ?? "",
|
|
359
|
-
Description: pkg.description ?? "",
|
|
459
|
+
DownloadTimeoutInSeconds: 300,
|
|
360
460
|
SkipAnalyze: String(opts.skipAnalyze),
|
|
361
461
|
SkipValidate: String(opts.skipValidate),
|
|
362
462
|
TargetFramework: context.targetFramework,
|
|
363
463
|
RpaProjects: rpaProjects,
|
|
364
464
|
WorkflowCompilerVersion: context.workflowCompilerVersion ?? "",
|
|
365
|
-
}
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
if (firstEntry.operation === BundleOperation.Pack) {
|
|
468
|
+
executorInfo.Configuration = context.configuration;
|
|
469
|
+
const pkg = firstEntry.options.package;
|
|
470
|
+
executorInfo.Package = {
|
|
471
|
+
Name: pkg.id,
|
|
472
|
+
Version: pkg.version,
|
|
473
|
+
Author: pkg.author ?? "",
|
|
474
|
+
Description: pkg.description ?? "",
|
|
475
|
+
ReleaseNotes: pkg.releaseNotes ?? "",
|
|
476
|
+
Tags: pkg.tags ?? "",
|
|
477
|
+
IconUrl: pkg.iconUrl ?? "",
|
|
478
|
+
ProjectUrl: pkg.projectUrl ?? "",
|
|
479
|
+
RepositoryType: pkg.repositoryType ?? "",
|
|
480
|
+
RepositoryUrl: pkg.repositoryUrl ?? "",
|
|
481
|
+
RepositoryBranch: pkg.repositoryBranch ?? "",
|
|
482
|
+
RepositoryCommit: pkg.repositoryCommit ?? "",
|
|
483
|
+
};
|
|
484
|
+
// Flat fields retained for backward compatibility with agents that
|
|
485
|
+
// predate the nested Package structure.
|
|
486
|
+
executorInfo.Name = pkg.id;
|
|
487
|
+
executorInfo.Version = pkg.version;
|
|
488
|
+
executorInfo.Author = pkg.author ?? "";
|
|
489
|
+
executorInfo.Description = pkg.description ?? "";
|
|
490
|
+
executorInfo.ReleaseNotes = pkg.releaseNotes ?? "";
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const inputArguments = JSON.stringify(executorInfo);
|
|
366
494
|
|
|
367
|
-
const body = {
|
|
495
|
+
const body: Record<string, unknown> = {
|
|
368
496
|
source: "StudioWeb",
|
|
369
497
|
targetFramework: context.targetFramework,
|
|
370
498
|
jobType: "PublishStudioProject",
|
|
371
|
-
inputArguments: executorInfo,
|
|
372
499
|
};
|
|
373
500
|
|
|
501
|
+
// The serverless jobs endpoint caps inline inputArguments at
|
|
502
|
+
// MAX_INLINE_INPUT_ARGUMENTS_LENGTH characters. For larger payloads we
|
|
503
|
+
// upload the arguments as a file attachment and reference it via
|
|
504
|
+
// inputFile instead (the two are mutually exclusive on the server).
|
|
505
|
+
if (
|
|
506
|
+
inputArguments.length >
|
|
507
|
+
ProjectBundleExecutor.MAX_INLINE_INPUT_ARGUMENTS_LENGTH
|
|
508
|
+
) {
|
|
509
|
+
context.logger?.info(
|
|
510
|
+
translate.t(
|
|
511
|
+
"toolWorkflowCompilerBrowser.info.offloadingInputArguments",
|
|
512
|
+
{ length: inputArguments.length },
|
|
513
|
+
),
|
|
514
|
+
);
|
|
515
|
+
body.inputFile = await this.uploadInputArgumentsFileAsync(
|
|
516
|
+
inputArguments,
|
|
517
|
+
connection,
|
|
518
|
+
context.logger,
|
|
519
|
+
);
|
|
520
|
+
} else {
|
|
521
|
+
body.inputArguments = inputArguments;
|
|
522
|
+
}
|
|
523
|
+
|
|
374
524
|
const headers: Record<string, string> = {
|
|
375
525
|
"Content-Type": "application/json",
|
|
376
526
|
Authorization: `Bearer ${connection.accessToken}`,
|
|
@@ -398,6 +548,86 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
398
548
|
}
|
|
399
549
|
}
|
|
400
550
|
|
|
551
|
+
/**
|
|
552
|
+
* Uploads the input arguments JSON as a file attachment and returns the
|
|
553
|
+
* attachment id, to be passed as `inputFile` on the serverless job request.
|
|
554
|
+
* Mirrors the two-step flow used by the Orchestrator UI: create the
|
|
555
|
+
* attachment (which returns a signed blob write URI) then PUT the contents
|
|
556
|
+
* to that URI using the storage-provided headers.
|
|
557
|
+
*/
|
|
558
|
+
private async uploadInputArgumentsFileAsync(
|
|
559
|
+
inputArguments: string,
|
|
560
|
+
connection: ConnectionInfo,
|
|
561
|
+
logger?: IToolLogger,
|
|
562
|
+
): Promise<string> {
|
|
563
|
+
const baseUrl = toRelativeUrl(connection.cloudUrl!);
|
|
564
|
+
const attachmentsUrl = `${baseUrl}/orchestrator_/odata/Attachments`;
|
|
565
|
+
|
|
566
|
+
const headers: Record<string, string> = {
|
|
567
|
+
"Content-Type": "application/json",
|
|
568
|
+
Authorization: `Bearer ${connection.accessToken}`,
|
|
569
|
+
"X-UIPATH-OrganizationUnitId": connection.folderId ?? "",
|
|
570
|
+
};
|
|
571
|
+
if (connection.tenantId) {
|
|
572
|
+
headers["x-uipath-tenantid"] = connection.tenantId;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const createResponse = await fetch(attachmentsUrl, {
|
|
576
|
+
method: "POST",
|
|
577
|
+
headers,
|
|
578
|
+
body: JSON.stringify({ name: "input.json" }),
|
|
579
|
+
});
|
|
580
|
+
if (!createResponse.ok) {
|
|
581
|
+
const errorText = await createResponse.text();
|
|
582
|
+
throw new Error(
|
|
583
|
+
translate.t(
|
|
584
|
+
"toolWorkflowCompilerBrowser.errors.createAttachmentFailed",
|
|
585
|
+
{ status: createResponse.status, errorText },
|
|
586
|
+
),
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const attachment = (await createResponse.json()) as AttachmentResponse;
|
|
591
|
+
const attachmentId = attachment.Id ?? attachment.id ?? "";
|
|
592
|
+
const writeUri =
|
|
593
|
+
attachment.BlobFileAccess?.Uri ?? attachment.blobFileAccess?.Uri;
|
|
594
|
+
if (!attachmentId || !writeUri) {
|
|
595
|
+
throw new Error(
|
|
596
|
+
translate.t(
|
|
597
|
+
"toolWorkflowCompilerBrowser.errors.attachmentResponseMalformed",
|
|
598
|
+
),
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// PUT the raw bytes to the SAS blob URI. The Azure blob endpoint
|
|
603
|
+
// requires the BlockBlob type header; matches the proven contract in
|
|
604
|
+
// `@uipath/orchestrator-sdk`'s uploadJobAttachment.
|
|
605
|
+
const uploadResponse = await fetch(writeUri, {
|
|
606
|
+
method: "PUT",
|
|
607
|
+
headers: {
|
|
608
|
+
"Content-Type": "application/octet-stream",
|
|
609
|
+
"x-ms-blob-type": "BlockBlob",
|
|
610
|
+
},
|
|
611
|
+
body: inputArguments,
|
|
612
|
+
});
|
|
613
|
+
if (!uploadResponse.ok) {
|
|
614
|
+
throw new Error(
|
|
615
|
+
translate.t(
|
|
616
|
+
"toolWorkflowCompilerBrowser.errors.uploadInputArgumentsFailed",
|
|
617
|
+
{
|
|
618
|
+
status: uploadResponse.status,
|
|
619
|
+
statusText: uploadResponse.statusText,
|
|
620
|
+
},
|
|
621
|
+
),
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
logger?.info(
|
|
626
|
+
`[BundleExecutor] Uploaded input arguments as attachment ${attachmentId}`,
|
|
627
|
+
);
|
|
628
|
+
return attachmentId;
|
|
629
|
+
}
|
|
630
|
+
|
|
401
631
|
private resolveAll(session: BundleSession, result: ToolResult): void {
|
|
402
632
|
for (const [, entry] of session.projects) {
|
|
403
633
|
entry.resolve(result);
|
|
@@ -405,7 +635,7 @@ export class ProjectBundleExecutor implements IProjectBundleExecutor {
|
|
|
405
635
|
}
|
|
406
636
|
|
|
407
637
|
private countCompatibleProjects(context: ProjectOperationContext): number {
|
|
408
|
-
return context.
|
|
638
|
+
return context.projects.filter(
|
|
409
639
|
(p) =>
|
|
410
640
|
p.ProjectPath != null &&
|
|
411
641
|
this.toolFactory.supportedTypes.includes(p.Type),
|
|
@@ -7,14 +7,16 @@ import {
|
|
|
7
7
|
type IToolLogger,
|
|
8
8
|
type ProjectOperationContext,
|
|
9
9
|
ProjectTool,
|
|
10
|
+
ToolErrorCodes,
|
|
10
11
|
ToolResult,
|
|
11
12
|
} from "@uipath/solutionpackager-tool-core";
|
|
12
13
|
import type { IProjectBundleExecutor } from "./project-bundle-executor.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Browser workflow compiler tool implementation.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* Delegates pack and validate to a bundle executor that coordinates a
|
|
18
|
+
* single remote-agent invocation across all compatible projects in the
|
|
19
|
+
* solution via SignalR.
|
|
18
20
|
*/
|
|
19
21
|
export class WorkflowCompilerTool extends ProjectTool {
|
|
20
22
|
constructor(
|
|
@@ -37,13 +39,17 @@ export class WorkflowCompilerTool extends ProjectTool {
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
async validateAsync(
|
|
40
|
-
|
|
42
|
+
options: IProjectValidateOptions,
|
|
41
43
|
_cancellationToken?: AbortSignal,
|
|
42
44
|
): Promise<ToolResult> {
|
|
43
|
-
this.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
if (!this.context) {
|
|
46
|
+
return ToolResult.error(
|
|
47
|
+
ToolErrorCodes.InternalError,
|
|
48
|
+
"Validate operation requires a project operation context",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return this.bundleExecutor.validateAsync(options, this.context);
|
|
47
53
|
}
|
|
48
54
|
|
|
49
55
|
async buildAsync(
|
|
@@ -61,10 +67,10 @@ export class WorkflowCompilerTool extends ProjectTool {
|
|
|
61
67
|
_cancellationToken?: AbortSignal,
|
|
62
68
|
): Promise<ToolResult> {
|
|
63
69
|
if (!this.context) {
|
|
64
|
-
|
|
70
|
+
return ToolResult.error(
|
|
71
|
+
ToolErrorCodes.InternalError,
|
|
65
72
|
"Pack operation requires a project operation context",
|
|
66
73
|
);
|
|
67
|
-
return ToolResult.success();
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
return this.bundleExecutor.packAsync(options, this.context);
|