@uipath/packager-tool-webapp 1.202.0-preview.159 → 1.203.0-preview.160

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.
@@ -0,0 +1,11 @@
1
+ import type { IFileSystem, ProjectResourceContribution } from "@uipath/solutionpackager-tool-core";
2
+ /**
3
+ * The AppV2 side of the project resource contribution contract: reads the
4
+ * project's own `webAppManifest.json` + `action-schema.json` and returns plain
5
+ * data. Never reads or writes the solution's resource JSON — solution-tool's
6
+ * driver does that (AGENTS.md Hard Rule #19).
7
+ *
8
+ * Errors are returned, not thrown, so one broken file reports alongside every
9
+ * other project's problems instead of aborting the walk.
10
+ */
11
+ export declare function describeActionApp(projectDir: string, fs: IFileSystem): Promise<ProjectResourceContribution>;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * AppV2 CodedAction domain — the file formats, the schema transform, and the
3
+ * project resource contribution built on them. Lives here (not in a `*-tool`)
4
+ * because AGENTS.md Hard Rule #19 puts a project type's formats at the layer
5
+ * that owns the type. Own subpath entry, node target, so the browser bundle in
6
+ * `src/index.ts` never pulls it.
7
+ *
8
+ * The subpath build keeps `zod`, `@uipath/common` and
9
+ * `@uipath/solutionpackager-tool-core` external. `@uipath/common` has to stay
10
+ * external — its singletons are shared across bundles through
11
+ * `Symbol.for()` keys, and a second inlined copy would split that state — and
12
+ * the other two follow the same rule the root entry already uses. All three
13
+ * are therefore declared as `peerDependencies` (the shape
14
+ * `packager-tool-flow` already uses for its own externals), so the published
15
+ * package states the contract instead of leaving bare imports for whatever
16
+ * host happens to provide them. So a consumer resolves them itself:
17
+ * `codedapp-tool` therefore declares `zod` in its own `devDependencies` even
18
+ * though nothing under `codedapp-tool/src` imports it, and `knip.json` lists
19
+ * it under that package's `ignoreDependencies` for exactly that reason. Root
20
+ * `tsconfig.base.json` aliases this subpath to source, so the consumer
21
+ * compiles these files and needs the dependency at build time, not just at
22
+ * runtime.
23
+ */
24
+ export { describeActionApp } from "./describe-action-app.js";
25
+ export { ACTION_SCHEMA_FILE_NAME, isActionApp, loadWebAppManifest, WEBAPP_MANIFEST_FILE_NAME, type WebAppManifestLoad, } from "./manifest-helpers.js";
26
+ export { parseActionSchema } from "./parse.js";
27
+ export { type JsonActionSchema, JsonActionSchemaValidator, JsonDataType, JsonFormatType, type JsonSchemaProperty, JsonSchemaPropertySchema, type ParsedActionPropertySchema, type ParsedActionSchema, VBDataType, VbArgumentCollectionType, VbArgumentDataTypeNamespace, } from "./types.js";
28
+ export { WebAppContributingToolFactory } from "./webapp-contributing-tool-factory.js";
@@ -0,0 +1,1063 @@
1
+ // src/action-schema/describe-action-app.ts
2
+ import { catchError as catchError2 } from "@uipath/common";
3
+
4
+ // src/action-schema/manifest-helpers.ts
5
+ import { catchError } from "@uipath/common";
6
+
7
+ // src/models/webapp-manifest.ts
8
+ var WebAppVariantType;
9
+ ((WebAppVariantType2) => {
10
+ WebAppVariantType2["Coded"] = "Coded";
11
+ WebAppVariantType2["JS"] = "JS";
12
+ })(WebAppVariantType ||= {});
13
+ var WEBAPP_MANIFEST_FILE_NAME = "webAppManifest.json";
14
+
15
+ // src/action-schema/manifest-helpers.ts
16
+ var ACTION_SCHEMA_FILE_NAME = "action-schema.json";
17
+ var VARIANTS = Object.values(WebAppVariantType);
18
+ var SUBTYPE_BY_VARIANT = {
19
+ ["Coded" /* Coded */]: {
20
+ app: "Coded" /* Coded */,
21
+ action: "CodedAction" /* CodedAction */
22
+ },
23
+ ["JS" /* JS */]: { app: "JS", action: "JS Action" }
24
+ };
25
+ var ACTION_SUBTYPES = new Set(Object.values(SUBTYPE_BY_VARIANT).map((row) => row.action));
26
+ async function loadWebAppManifest(fs, projectDir) {
27
+ const manifestPath = fs.path.join(projectDir, WEBAPP_MANIFEST_FILE_NAME);
28
+ const [readError, raw] = await catchError(fs.readFile(manifestPath, "utf-8"));
29
+ if (readError)
30
+ return { state: "invalid", reason: readError.message };
31
+ if (raw === null || raw === undefined)
32
+ return { state: "missing" };
33
+ if (raw === "")
34
+ return { state: "invalid", reason: "the file is empty" };
35
+ const [parseError, parsed] = catchError(() => JSON.parse(raw));
36
+ if (parseError)
37
+ return { state: "invalid", reason: parseError.message };
38
+ const shapeError = manifestShapeError(parsed);
39
+ if (shapeError)
40
+ return { state: "invalid", reason: shapeError };
41
+ return { state: "ok", manifest: parsed };
42
+ }
43
+ function manifestShapeError(parsed) {
44
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
45
+ return "the file is not a JSON object";
46
+ }
47
+ const type = parsed.type;
48
+ if (typeof type !== "string" || !VARIANTS.includes(type)) {
49
+ return `"type" must be one of ${VARIANTS.join(", ")} (got ${JSON.stringify(type)})`;
50
+ }
51
+ return;
52
+ }
53
+ function isActionApp(manifest) {
54
+ if (!manifest)
55
+ return false;
56
+ if (ACTION_SUBTYPES.has(manifest.solutionResourceSubType))
57
+ return true;
58
+ const config = manifest.config;
59
+ return config?.isActionApp === true;
60
+ }
61
+ function appSubTypeFor(manifest) {
62
+ const row = SUBTYPE_BY_VARIANT[manifest?.type ?? "Coded" /* Coded */];
63
+ return isActionApp(manifest) ? row.action : row.app;
64
+ }
65
+
66
+ // src/action-schema/parse.ts
67
+ import { z as z2 } from "zod";
68
+
69
+ // src/action-schema/types.ts
70
+ import { z } from "zod";
71
+ var JsonDataType;
72
+ ((JsonDataType2) => {
73
+ JsonDataType2["string"] = "string";
74
+ JsonDataType2["integer"] = "integer";
75
+ JsonDataType2["number"] = "number";
76
+ JsonDataType2["boolean"] = "boolean";
77
+ JsonDataType2["array"] = "array";
78
+ JsonDataType2["object"] = "object";
79
+ JsonDataType2["file"] = "file";
80
+ JsonDataType2["ContentValidationData"] = "ContentValidationData";
81
+ })(JsonDataType ||= {});
82
+ var JsonFormatType;
83
+ ((JsonFormatType2) => {
84
+ JsonFormatType2["uuid"] = "uuid";
85
+ JsonFormatType2["date"] = "date";
86
+ })(JsonFormatType ||= {});
87
+ var VbArgumentCollectionType;
88
+ ((VbArgumentCollectionType2) => {
89
+ VbArgumentCollectionType2["array"] = "Array";
90
+ })(VbArgumentCollectionType ||= {});
91
+ var VbArgumentDataTypeNamespace;
92
+ ((VbArgumentDataTypeNamespace2) => {
93
+ VbArgumentDataTypeNamespace2["system"] = "system";
94
+ })(VbArgumentDataTypeNamespace ||= {});
95
+ var VBDataType;
96
+ ((VBDataType2) => {
97
+ VBDataType2["string"] = "System.String";
98
+ VBDataType2["int64"] = "System.Int64";
99
+ VBDataType2["boolean"] = "System.Boolean";
100
+ VBDataType2["decimal"] = "System.Decimal";
101
+ VBDataType2["dateOnly"] = "System.DateOnly";
102
+ VBDataType2["guid"] = "System.Guid";
103
+ VBDataType2["object"] = "System.Object";
104
+ VBDataType2["iresource"] = "UiPath.Platform.ResourceHandling.IResource";
105
+ VBDataType2["ContentValidationData"] = "UiPath.DocumentProcessing.Contracts.Actions.ContentValidationData";
106
+ })(VBDataType ||= {});
107
+ var JsonSchemaPropertySchema = z.lazy(() => z.object({
108
+ type: z.enum([
109
+ "string" /* string */,
110
+ "integer" /* integer */,
111
+ "number" /* number */,
112
+ "boolean" /* boolean */,
113
+ "array" /* array */,
114
+ "object" /* object */,
115
+ "file" /* file */,
116
+ "ContentValidationData" /* ContentValidationData */
117
+ ], {
118
+ message: "Invalid property type — expected string, integer, number, boolean, array, object, file, or ContentValidationData"
119
+ }),
120
+ required: z.boolean().optional(),
121
+ description: z.string().optional(),
122
+ format: z.enum(["uuid" /* uuid */, "date" /* date */], {
123
+ message: "Invalid property format — expected uuid or date"
124
+ }).optional(),
125
+ items: JsonSchemaPropertySchema.optional(),
126
+ properties: z.record(z.string(), JsonSchemaPropertySchema).optional()
127
+ }).refine((data) => data.type !== "array" /* array */ || !!data.items, {
128
+ message: "array type requires an `items` schema"
129
+ }).refine((data) => !data.format || data.type === "string" /* string */, {
130
+ message: "`format` is only valid on string types"
131
+ }).refine((data) => data.type !== "array" /* array */ || !data.items || data.items.type !== "array" /* array */, {
132
+ message: "nested arrays are not supported"
133
+ }));
134
+ var JsonSchemaObjectSchema = z.object({
135
+ type: z.literal("object", {
136
+ message: "action-schema sections must have type: 'object'"
137
+ }),
138
+ properties: z.record(z.string(), JsonSchemaPropertySchema, {
139
+ message: "section `properties` must be a string-keyed object"
140
+ })
141
+ });
142
+ var OutcomesSectionSchema = z.object({
143
+ type: z.literal("object", {
144
+ message: "action-schema sections must have type: 'object'"
145
+ }),
146
+ properties: z.record(z.string(), z.looseObject({}).optional().default({}), {
147
+ message: "section `properties` must be a string-keyed object"
148
+ })
149
+ });
150
+ var JsonActionSchemaValidator = z.object({
151
+ inputs: JsonSchemaObjectSchema,
152
+ outputs: JsonSchemaObjectSchema,
153
+ inOuts: JsonSchemaObjectSchema,
154
+ outcomes: OutcomesSectionSchema
155
+ }, {
156
+ message: "action-schema.json must define `inputs`, `outputs`, `inOuts`, and `outcomes`"
157
+ });
158
+
159
+ // src/action-schema/parse.ts
160
+ function parseActionSchema(raw) {
161
+ const parsed = JSON.parse(raw);
162
+ const validated = validate(parsed);
163
+ return transformToParsedSchema(validated);
164
+ }
165
+ function validate(schema) {
166
+ try {
167
+ return JsonActionSchemaValidator.parse(schema);
168
+ } catch (err) {
169
+ if (err instanceof z2.ZodError) {
170
+ const details = err.issues.map((issue) => {
171
+ const path = issue.path.length > 0 ? issue.path.join(".") : "root";
172
+ return ` - ${path}: ${issue.message}`;
173
+ }).join(`
174
+ `);
175
+ throw new Error(`Invalid action-schema.json:
176
+ ${details}`);
177
+ }
178
+ throw err;
179
+ }
180
+ }
181
+ function fnv1a32(text, seed = 0) {
182
+ let hash = (2166136261 ^ seed) >>> 0;
183
+ for (let i = 0;i < text.length; i++) {
184
+ hash = (hash ^ text.charCodeAt(i)) >>> 0;
185
+ hash = hash + (hash << 1 >>> 0) + (hash << 4 >>> 0) + (hash << 7 >>> 0) + (hash << 8 >>> 0) + (hash << 24 >>> 0) >>> 0;
186
+ }
187
+ return hash >>> 0;
188
+ }
189
+ function hex32(n) {
190
+ return n.toString(16).padStart(8, "0");
191
+ }
192
+ function deterministicUuid(path) {
193
+ const a = hex32(fnv1a32(path, 0));
194
+ const b = hex32(fnv1a32(path, 1));
195
+ const c = hex32(fnv1a32(path, 2));
196
+ const d = hex32(fnv1a32(path, 3));
197
+ const timeLow = a;
198
+ const timeMid = b.slice(0, 4);
199
+ const timeHiAndVersion = `5${b.slice(5, 8)}`;
200
+ const variantBits = (parseInt(c[0], 16) & 3 | 8).toString(16);
201
+ const clockSeq = `${variantBits}${c.slice(1, 4)}`;
202
+ const node = `${c.slice(4, 8)}${d}`;
203
+ return `${timeLow}-${timeMid}-${timeHiAndVersion}-${clockSeq}-${node}`;
204
+ }
205
+ function mapJsonTypeToSystemType(type, format) {
206
+ if (format === "uuid" /* uuid */)
207
+ return "System.Guid" /* guid */;
208
+ if (format === "date" /* date */)
209
+ return "System.DateOnly" /* dateOnly */;
210
+ switch (type) {
211
+ case "string" /* string */:
212
+ return "System.String" /* string */;
213
+ case "integer" /* integer */:
214
+ return "System.Int64" /* int64 */;
215
+ case "number" /* number */:
216
+ return "System.Decimal" /* decimal */;
217
+ case "boolean" /* boolean */:
218
+ return "System.Boolean" /* boolean */;
219
+ case "object" /* object */:
220
+ return "System.Object" /* object */;
221
+ case "file" /* file */:
222
+ return "UiPath.Platform.ResourceHandling.IResource" /* iresource */;
223
+ case "ContentValidationData" /* ContentValidationData */:
224
+ return "UiPath.DocumentProcessing.Contracts.Actions.ContentValidationData" /* ContentValidationData */;
225
+ default:
226
+ throw new Error(`Unsupported action schema JSON data type: ${type}`);
227
+ }
228
+ }
229
+ function transformProperty(path, name, propDef) {
230
+ const isArray = propDef.type === "array" /* array */;
231
+ const itemType = isArray && propDef.items ? propDef.items.type : propDef.type;
232
+ const itemFormat = isArray && propDef.items ? propDef.items.format : propDef.format;
233
+ let properties = [];
234
+ if (propDef.type === "object" /* object */ && propDef.properties) {
235
+ properties = Object.keys(propDef.properties).map((child) => transformProperty(`${path}.${child}`, child, propDef.properties?.[child]));
236
+ } else if (propDef.type === "array" /* array */ && propDef.items && propDef.items.type === "object" /* object */ && propDef.items.properties) {
237
+ const nested = propDef.items.properties;
238
+ properties = Object.keys(nested).map((child) => transformProperty(`${path}[].${child}`, child, nested[child]));
239
+ }
240
+ return {
241
+ name,
242
+ key: deterministicUuid(path),
243
+ required: propDef.required ?? false,
244
+ description: propDef.description,
245
+ version: 0,
246
+ typeNamespace: "system" /* system */,
247
+ isList: isArray,
248
+ collectionDataType: isArray ? "Array" /* array */ : null,
249
+ type: mapJsonTypeToSystemType(itemType, itemFormat),
250
+ properties
251
+ };
252
+ }
253
+ function transformToParsedSchema(schema) {
254
+ const transformSection = (section, sectionName) => section?.properties ? Object.keys(section.properties).map((name) => transformProperty(`${sectionName}.${name}`, name, section.properties[name])) : [];
255
+ const outcomes = schema.outcomes?.properties ? Object.keys(schema.outcomes.properties).map((name) => ({
256
+ name,
257
+ key: deterministicUuid(`outcomes.${name}`),
258
+ required: false,
259
+ type: "System.String" /* string */,
260
+ typeNamespace: "system" /* system */,
261
+ isList: false,
262
+ properties: [],
263
+ version: 0
264
+ })) : [];
265
+ return {
266
+ key: deterministicUuid("root"),
267
+ version: 0,
268
+ description: "Action Schema",
269
+ id: `ID${deterministicUuid("root.id").replace(/-/g, "")}`,
270
+ name: "ActionSchema",
271
+ inputs: transformSection(schema.inputs, "inputs"),
272
+ outputs: transformSection(schema.outputs, "outputs"),
273
+ inOuts: transformSection(schema.inOuts, "inOuts"),
274
+ outcomes
275
+ };
276
+ }
277
+
278
+ // src/action-schema/describe-action-app.ts
279
+ var ARTEFACT_KIND_APP = "app";
280
+ var SPEC_KEY_ACTION_SCHEMA = "actionSchema";
281
+ async function describeActionApp(projectDir, fs) {
282
+ const load = await loadWebAppManifest(fs, projectDir);
283
+ if (load.state === "invalid") {
284
+ const manifestPath = fs.path.join(projectDir, WEBAPP_MANIFEST_FILE_NAME);
285
+ return {
286
+ errors: [
287
+ {
288
+ code: "webapp_manifest_invalid",
289
+ message: `${WEBAPP_MANIFEST_FILE_NAME} at ${manifestPath} could not be read: ${load.reason}.`,
290
+ instructions: `Make ${manifestPath} readable and a valid manifest (a JSON object whose "type" is Coded or JS), or re-scaffold the project with 'uip codedapp init <project-path>', then re-run the command.`
291
+ }
292
+ ]
293
+ };
294
+ }
295
+ const manifest = load.state === "ok" ? load.manifest : null;
296
+ const projectSubType = appSubTypeFor(manifest);
297
+ if (!isActionApp(manifest)) {
298
+ return {
299
+ projectSubType,
300
+ specPatch: [
301
+ {
302
+ kind: ARTEFACT_KIND_APP,
303
+ values: { [SPEC_KEY_ACTION_SCHEMA]: null }
304
+ }
305
+ ]
306
+ };
307
+ }
308
+ const schemaPath = fs.path.join(projectDir, ACTION_SCHEMA_FILE_NAME);
309
+ const [readError, raw] = await catchError2(fs.readFile(schemaPath, "utf-8"));
310
+ if (readError) {
311
+ return {
312
+ projectSubType,
313
+ errors: [
314
+ {
315
+ code: "action_schema_unreadable",
316
+ message: `${ACTION_SCHEMA_FILE_NAME} at ${schemaPath} could not be read: ${readError.message}.`,
317
+ instructions: `Make ${schemaPath} readable, then re-run the command.`
318
+ }
319
+ ]
320
+ };
321
+ }
322
+ if (raw === null || raw === undefined) {
323
+ return {
324
+ projectSubType,
325
+ errors: [
326
+ {
327
+ code: "action_schema_missing",
328
+ message: `Coded Action project is missing ${ACTION_SCHEMA_FILE_NAME}: ${schemaPath}.`,
329
+ instructions: `Create ${ACTION_SCHEMA_FILE_NAME} defining inputs / outputs / inOuts / outcomes, then re-run the command.`
330
+ }
331
+ ]
332
+ };
333
+ }
334
+ const [parseError, parsed] = catchError2(() => parseActionSchema(raw));
335
+ if (parseError) {
336
+ return {
337
+ projectSubType,
338
+ errors: [
339
+ {
340
+ code: "action_schema_invalid",
341
+ message: `${ACTION_SCHEMA_FILE_NAME} at ${schemaPath} is not a valid action schema: ${parseError.message}`,
342
+ instructions: `Fix the reported section or property in ${schemaPath}, then re-run the command.`
343
+ }
344
+ ]
345
+ };
346
+ }
347
+ return {
348
+ projectSubType,
349
+ specPatch: [
350
+ {
351
+ kind: ARTEFACT_KIND_APP,
352
+ values: { [SPEC_KEY_ACTION_SCHEMA]: JSON.stringify(parsed) }
353
+ }
354
+ ]
355
+ };
356
+ }
357
+ // src/webapp-tool-factory.ts
358
+ import {
359
+ ProjectTypes as ProjectTypes3
360
+ } from "@uipath/solutionpackager-tool-core";
361
+
362
+ // src/webapp-tool.ts
363
+ import {
364
+ Path as Path5,
365
+ ProjectTool,
366
+ TemporaryStorageService,
367
+ ToolErrorCodes,
368
+ ToolResult
369
+ } from "@uipath/solutionpackager-tool-core";
370
+
371
+ // src/constants.ts
372
+ var PROJECT_JSON_FILE = "project.json";
373
+ var DEFAULT_BUNDLE_PATH = "source/dist";
374
+ var APP_FOLDER_NAME = ".app";
375
+ var CONTENT_APP_FOLDER_NAME = "app";
376
+ var TARGET_RUNTIME = "Coded";
377
+ var TARGET_JS_RUNTIME = "JS";
378
+ var DEFAULT_ENTRY_POINT_TYPE = "api";
379
+ var ERROR_MESSAGES = {
380
+ MANIFEST_NOT_FOUND: (file) => `WebApp manifest not found: ${file}. This file is required for WebApp projects.`,
381
+ PROJECT_JSON_FOUND: "project.json found in WebApp project. The WebApp tool only supports Coded web apps without project.json.",
382
+ MANIFEST_LOAD_FAILED: (file) => `Failed to load or parse ${file}`,
383
+ BUNDLE_NOT_FOUND: (path) => `Compiled bundle not found at ${path}. Ensure the project is built before packing.`,
384
+ BUNDLE_NOT_DIRECTORY: (path) => `Bundle path ${path} exists but is not a directory.`,
385
+ APP_FOLDER_NOT_FOUND: (path) => `.app folder not found at ${path}. Ensure the project contains a .app folder.`,
386
+ APP_FOLDER_NOT_DIRECTORY: (path) => `.app path ${path} exists but is not a directory.`,
387
+ BUILD_NOT_SUPPORTED: "Build execution (isCompiled=false) is not yet supported. Please build the project manually and set isCompiled=true.",
388
+ VALIDATION_FAILED: (context) => `Validation failed: ${context}`,
389
+ PACKING_FAILED: (context) => `An error occurred while packing WebApp project: ${context}`,
390
+ PACKAGE_NAME_REQUIRED: "Package name is required",
391
+ PACKAGE_VERSION_REQUIRED: "Package version is required",
392
+ PROJECT_PATH_REQUIRED: "Project path is required",
393
+ OUTPUT_PATH_REQUIRED: "Output path is required"
394
+ };
395
+
396
+ // src/strategies/coded-app-strategy.ts
397
+ import {
398
+ NugetConstants,
399
+ NugetPackager,
400
+ Path as Path3,
401
+ ProjectTypes,
402
+ TargetFramework
403
+ } from "@uipath/solutionpackager-tool-core";
404
+
405
+ // src/utils/fs-helpers.ts
406
+ import { Path } from "@uipath/solutionpackager-tool-core";
407
+ async function copyDirectoryAsync(fileSystem, sourcePath, destinationPath) {
408
+ await fileSystem.mkdir(destinationPath);
409
+ const entries = await fileSystem.readdir(sourcePath);
410
+ for (const entry of entries) {
411
+ const sourceEntry = Path.join(sourcePath, entry);
412
+ const destEntry = Path.join(destinationPath, entry);
413
+ const stat = await fileSystem.stat(sourceEntry);
414
+ if (stat?.isDirectory()) {
415
+ await copyDirectoryAsync(fileSystem, sourceEntry, destEntry);
416
+ } else if (stat?.isFile()) {
417
+ const content = await fileSystem.readFile(sourceEntry);
418
+ if (content) {
419
+ await fileSystem.writeFile(destEntry, content);
420
+ }
421
+ }
422
+ }
423
+ }
424
+
425
+ // src/utils/manifest-loader.ts
426
+ import { Path as Path2 } from "@uipath/solutionpackager-tool-core";
427
+ async function loadWebAppManifest2(fileSystem, projectPath) {
428
+ const manifestPath = Path2.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
429
+ const exists = await fileSystem.exists(manifestPath);
430
+ if (!exists) {
431
+ return null;
432
+ }
433
+ const content = await fileSystem.readFile(manifestPath);
434
+ if (!content) {
435
+ return null;
436
+ }
437
+ try {
438
+ const text = new TextDecoder().decode(content);
439
+ const manifest = JSON.parse(text);
440
+ return manifest;
441
+ } catch (error) {
442
+ throw new Error(`Failed to parse ${WEBAPP_MANIFEST_FILE_NAME}: ${error instanceof Error ? error.message : String(error)}`);
443
+ }
444
+ }
445
+ async function ensureWebAppProjectId(fileSystem, projectPath) {
446
+ const manifest = await loadWebAppManifest2(fileSystem, projectPath);
447
+ if (manifest && typeof manifest.projectId === "string" && manifest.projectId.length > 0) {
448
+ return manifest.projectId;
449
+ }
450
+ const id = crypto.randomUUID();
451
+ if (manifest) {
452
+ const updated = { ...manifest, projectId: id };
453
+ const manifestPath = Path2.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
454
+ await fileSystem.writeFile(manifestPath, `${JSON.stringify(updated, null, 2)}
455
+ `);
456
+ }
457
+ return id;
458
+ }
459
+
460
+ // src/strategies/coded-app-strategy.ts
461
+ class CodedAppStrategy {
462
+ fileSystem;
463
+ constructor(fileSystem) {
464
+ this.fileSystem = fileSystem;
465
+ }
466
+ async validateAsync(args) {
467
+ const { projectPath, manifest, logger } = args;
468
+ const typed = manifest;
469
+ let bundlePath = typed.config?.bundlePath;
470
+ if (typeof bundlePath !== "string" || bundlePath.length === 0) {
471
+ bundlePath = DEFAULT_BUNDLE_PATH;
472
+ }
473
+ const isCompiled = typed.config?.isCompiled ?? true;
474
+ if (isCompiled) {
475
+ const fullBundlePath = Path3.join(projectPath, bundlePath);
476
+ const exists = await this.fileSystem.exists(fullBundlePath);
477
+ if (!exists) {
478
+ const message = ERROR_MESSAGES.BUNDLE_NOT_FOUND(fullBundlePath);
479
+ const warnable = logger;
480
+ if (warnable?.warn) {
481
+ warnable.warn(message);
482
+ } else {
483
+ logger?.info(`Warning: ${message}`);
484
+ }
485
+ }
486
+ }
487
+ }
488
+ async packageAsync(args) {
489
+ const { projectPath, manifest, outputPath, packageInfo, logger } = args;
490
+ logger?.info(`Packaging Coded variant: ${packageInfo.id}@${packageInfo.version}`);
491
+ let bundlePath = manifest.config?.bundlePath;
492
+ if (typeof bundlePath !== "string" || bundlePath.length === 0) {
493
+ bundlePath = DEFAULT_BUNDLE_PATH;
494
+ }
495
+ const isCompiled = manifest.config?.isCompiled ?? true;
496
+ const fullBundlePath = Path3.join(projectPath, bundlePath);
497
+ if (isCompiled) {
498
+ logger?.progress("Validating compiled bundle...");
499
+ const bundleExists = await this.fileSystem.exists(fullBundlePath);
500
+ if (!bundleExists) {
501
+ throw new Error(ERROR_MESSAGES.BUNDLE_NOT_FOUND(fullBundlePath));
502
+ }
503
+ const bundleStat = await this.fileSystem.stat(fullBundlePath);
504
+ if (!bundleStat?.isDirectory()) {
505
+ throw new Error(ERROR_MESSAGES.BUNDLE_NOT_DIRECTORY(fullBundlePath));
506
+ }
507
+ } else {
508
+ logger?.info("Build mode (isCompiled=false) is not yet implemented in v1.");
509
+ throw new Error(ERROR_MESSAGES.BUILD_NOT_SUPPORTED);
510
+ }
511
+ const localBuildFolder = Path3.join(outputPath, NugetConstants.OutputFolderName);
512
+ const contentFolder = Path3.join(localBuildFolder, NugetConstants.ContentFolderName);
513
+ await this.fileSystem.mkdir(contentFolder);
514
+ try {
515
+ logger?.progress("Copying bundle to content folder...");
516
+ await copyDirectoryAsync(this.fileSystem, fullBundlePath, contentFolder);
517
+ logger?.progress("Preparing metadata files...");
518
+ await this.prepareMetadataFiles(localBuildFolder, contentFolder, packageInfo, manifest, projectPath);
519
+ logger?.progress("Creating NuGet package...");
520
+ const nupkgFileName = `${packageInfo.id}.${packageInfo.version}.nupkg`;
521
+ const nupkgPath = Path3.join(outputPath, nupkgFileName);
522
+ const packager = new NugetPackager(this.fileSystem);
523
+ const result = await packager.packAsync(localBuildFolder, packageInfo, nupkgPath);
524
+ logger?.info(`Package created successfully: ${result.outputPath}`);
525
+ return result.outputPath;
526
+ } finally {
527
+ try {
528
+ await this.fileSystem.rm(localBuildFolder);
529
+ } catch (cleanupError) {
530
+ logger?.error(`Failed to cleanup build folder: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
531
+ }
532
+ }
533
+ }
534
+ async prepareMetadataFiles(_localBuildFolder, contentFolder, _packageInfo, _manifest, projectPath) {
535
+ let mainFile = "index.html";
536
+ const indexHtmlPath = Path3.join(contentFolder, "index.html");
537
+ const indexHtmlExists = await this.fileSystem.exists(indexHtmlPath);
538
+ if (!indexHtmlExists) {
539
+ const possibleEntries = ["index.html", "main.html", "app.html"];
540
+ for (const entry of possibleEntries) {
541
+ const entryPath = Path3.join(contentFolder, entry);
542
+ if (await this.fileSystem.exists(entryPath)) {
543
+ mainFile = entry;
544
+ break;
545
+ }
546
+ }
547
+ }
548
+ const operatePath = Path3.join(contentFolder, NugetConstants.OperateFileName);
549
+ const operateModel = {
550
+ projectId: await ensureWebAppProjectId(this.fileSystem, projectPath),
551
+ main: mainFile,
552
+ contentType: ProjectTypes.WebApp,
553
+ targetFramework: TargetFramework.Portable,
554
+ targetRuntime: TARGET_RUNTIME,
555
+ runtimeOptions: {
556
+ requiresUserInteraction: false,
557
+ isAttended: false
558
+ }
559
+ };
560
+ const operateJson = JSON.stringify(operateModel, null, 2);
561
+ await this.fileSystem.writeFile(operatePath, operateJson);
562
+ const manifestSourcePath = Path3.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
563
+ const manifestDestPath = Path3.join(contentFolder, WEBAPP_MANIFEST_FILE_NAME);
564
+ const manifestExists = await this.fileSystem.exists(manifestSourcePath);
565
+ if (manifestExists) {
566
+ const manifestContent = await this.fileSystem.readFile(manifestSourcePath, "utf-8");
567
+ if (manifestContent) {
568
+ await this.fileSystem.writeFile(manifestDestPath, manifestContent);
569
+ }
570
+ }
571
+ const uipathJsonSourcePath = Path3.join(projectPath, "uipath.json");
572
+ const uipathJsonDestPath = Path3.join(contentFolder, "uipath.json");
573
+ const uipathJsonExists = await this.fileSystem.exists(uipathJsonSourcePath);
574
+ if (uipathJsonExists) {
575
+ const uipathJsonContent = await this.fileSystem.readFile(uipathJsonSourcePath, "utf-8");
576
+ if (uipathJsonContent) {
577
+ await this.fileSystem.writeFile(uipathJsonDestPath, uipathJsonContent);
578
+ }
579
+ }
580
+ const actionSchemaSourcePath = Path3.join(projectPath, "action-schema.json");
581
+ const actionSchemaDestPath = Path3.join(contentFolder, "action-schema.json");
582
+ const actionSchemaExists = await this.fileSystem.exists(actionSchemaSourcePath);
583
+ if (actionSchemaExists) {
584
+ const actionSchemaContent = await this.fileSystem.readFile(actionSchemaSourcePath, "utf-8");
585
+ if (actionSchemaContent) {
586
+ await this.fileSystem.writeFile(actionSchemaDestPath, actionSchemaContent);
587
+ }
588
+ }
589
+ const bindingsPath = Path3.join(contentFolder, "bindings.json");
590
+ const bindingsExists = await this.fileSystem.exists(bindingsPath);
591
+ if (!bindingsExists) {
592
+ const bindingsJson = JSON.stringify({
593
+ version: "1.0",
594
+ resources: []
595
+ }, null, 2);
596
+ await this.fileSystem.writeFile(bindingsPath, bindingsJson);
597
+ }
598
+ const bindingsV2Path = Path3.join(contentFolder, "bindings_v2.json");
599
+ const bindingsCandidatePaths = [
600
+ Path3.join(projectPath, "source", "bindings_v2.json"),
601
+ Path3.join(projectPath, "source", "bindings.json"),
602
+ Path3.join(projectPath, "bindings.json"),
603
+ Path3.join(projectPath, "bindings_v2.json")
604
+ ];
605
+ let bindingsV2Json = null;
606
+ for (const candidate of bindingsCandidatePaths) {
607
+ if (await this.fileSystem.exists(candidate)) {
608
+ bindingsV2Json = await this.fileSystem.readFile(candidate, "utf-8");
609
+ if (bindingsV2Json)
610
+ break;
611
+ }
612
+ }
613
+ if (!bindingsV2Json && await this.fileSystem.exists(bindingsV2Path)) {
614
+ bindingsV2Json = await this.fileSystem.readFile(bindingsV2Path, "utf-8");
615
+ }
616
+ if (!bindingsV2Json) {
617
+ bindingsV2Json = JSON.stringify({
618
+ version: "2.0",
619
+ resources: []
620
+ }, null, 2);
621
+ }
622
+ await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
623
+ const entryPointsPath = Path3.join(contentFolder, "entry-points.json");
624
+ const projectEntryPointsPath = Path3.join(projectPath, "entry-points.json");
625
+ let entryPointsContent;
626
+ const projectEntryPointsExists = await this.fileSystem.exists(projectEntryPointsPath);
627
+ if (projectEntryPointsExists) {
628
+ const entryPointsData = await this.fileSystem.readFile(projectEntryPointsPath, "utf-8");
629
+ if (entryPointsData) {
630
+ entryPointsContent = entryPointsData;
631
+ } else {
632
+ entryPointsContent = this.createDefaultEntryPoints(mainFile);
633
+ }
634
+ } else {
635
+ entryPointsContent = this.createDefaultEntryPoints(mainFile);
636
+ }
637
+ await this.fileSystem.writeFile(entryPointsPath, entryPointsContent);
638
+ const packageDescriptorPath = Path3.join(contentFolder, NugetConstants.PackageDescriptorFileName);
639
+ const packageDescriptor = {
640
+ $schema: "https://cloud.uipath.com/draft/2024-12/package-descriptor",
641
+ files: {
642
+ [NugetConstants.OperateFileName]: Path3.join(NugetConstants.ContentFolderName, NugetConstants.OperateFileName),
643
+ "entry-points.json": Path3.join(NugetConstants.ContentFolderName, "entry-points.json"),
644
+ "bindings.json": Path3.join(NugetConstants.ContentFolderName, "bindings_v2.json")
645
+ }
646
+ };
647
+ const packageDescriptorJson = JSON.stringify(packageDescriptor, null, 2);
648
+ await this.fileSystem.writeFile(packageDescriptorPath, packageDescriptorJson);
649
+ }
650
+ createDefaultEntryPoints(mainFile) {
651
+ const uniqueId = this.generateUniqueId();
652
+ const entryPoints = {
653
+ $schema: "https://cloud.uipath.com/draft/2024-12/entry-point",
654
+ $id: "entry-points-doc-001",
655
+ entryPoints: [
656
+ {
657
+ filePath: mainFile,
658
+ uniqueId,
659
+ type: DEFAULT_ENTRY_POINT_TYPE,
660
+ input: {
661
+ amount: { type: "integer" },
662
+ id: { type: "string" }
663
+ },
664
+ output: {
665
+ status: { type: "string" }
666
+ }
667
+ }
668
+ ]
669
+ };
670
+ return JSON.stringify(entryPoints, null, 2);
671
+ }
672
+ generateUniqueId() {
673
+ const randomBytes = new Uint8Array(16);
674
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
675
+ crypto.getRandomValues(randomBytes);
676
+ } else {
677
+ throw new Error("crypto.getRandomValues is not available");
678
+ }
679
+ randomBytes[6] = randomBytes[6] & 15 | 64;
680
+ randomBytes[8] = randomBytes[8] & 63 | 128;
681
+ const hex = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
682
+ return [
683
+ hex.substring(0, 8),
684
+ hex.substring(8, 12),
685
+ hex.substring(12, 16),
686
+ hex.substring(16, 20),
687
+ hex.substring(20, 32)
688
+ ].join("-");
689
+ }
690
+ }
691
+
692
+ // src/strategies/js-apps-strategy.ts
693
+ import {
694
+ NugetConstants as NugetConstants2,
695
+ NugetPackager as NugetPackager2,
696
+ Path as Path4,
697
+ ProjectTypes as ProjectTypes2,
698
+ TargetFramework as TargetFramework2
699
+ } from "@uipath/solutionpackager-tool-core";
700
+ class JsAppsStrategy {
701
+ fileSystem;
702
+ constructor(fileSystem) {
703
+ this.fileSystem = fileSystem;
704
+ }
705
+ async validateAsync(args) {
706
+ const { projectPath, logger } = args;
707
+ const appFolder = Path4.join(projectPath, APP_FOLDER_NAME);
708
+ const exists = await this.fileSystem.exists(appFolder);
709
+ if (!exists) {
710
+ const message = ERROR_MESSAGES.APP_FOLDER_NOT_FOUND(appFolder);
711
+ if (logger?.warn) {
712
+ logger.warn(message);
713
+ } else {
714
+ logger?.info(`Warning: ${message}`);
715
+ }
716
+ return;
717
+ }
718
+ const stat = await this.fileSystem.stat(appFolder);
719
+ if (!stat?.isDirectory()) {
720
+ const message = ERROR_MESSAGES.APP_FOLDER_NOT_DIRECTORY(appFolder);
721
+ if (logger?.warn) {
722
+ logger.warn(message);
723
+ } else {
724
+ logger?.info(`Warning: ${message}`);
725
+ }
726
+ }
727
+ }
728
+ async packageAsync(args) {
729
+ const { projectPath, manifest, outputPath, packageInfo, logger } = args;
730
+ logger?.info(`Packaging JS variant: ${packageInfo.id}@${packageInfo.version}`);
731
+ const appFolder = Path4.join(projectPath, APP_FOLDER_NAME);
732
+ logger?.progress("Validating .app folder...");
733
+ const appFolderExists = await this.fileSystem.exists(appFolder);
734
+ if (!appFolderExists) {
735
+ throw new Error(ERROR_MESSAGES.APP_FOLDER_NOT_FOUND(appFolder));
736
+ }
737
+ const appFolderStat = await this.fileSystem.stat(appFolder);
738
+ if (!appFolderStat?.isDirectory()) {
739
+ throw new Error(ERROR_MESSAGES.APP_FOLDER_NOT_DIRECTORY(appFolder));
740
+ }
741
+ const localBuildFolder = Path4.join(outputPath, NugetConstants2.OutputFolderName);
742
+ const contentFolder = Path4.join(localBuildFolder, NugetConstants2.ContentFolderName);
743
+ const contentAppFolder = Path4.join(contentFolder, CONTENT_APP_FOLDER_NAME);
744
+ await this.fileSystem.mkdir(contentFolder);
745
+ try {
746
+ logger?.progress("Copying .app folder into content/app...");
747
+ await copyDirectoryAsync(this.fileSystem, appFolder, contentAppFolder);
748
+ logger?.progress("Preparing metadata files...");
749
+ await this.prepareMetadataFiles(contentFolder, contentAppFolder, packageInfo, manifest, projectPath);
750
+ logger?.progress("Creating NuGet package...");
751
+ const nupkgFileName = `${packageInfo.id}.${packageInfo.version}.nupkg`;
752
+ const nupkgPath = Path4.join(outputPath, nupkgFileName);
753
+ const packager = new NugetPackager2(this.fileSystem);
754
+ const result = await packager.packAsync(localBuildFolder, packageInfo, nupkgPath);
755
+ logger?.info(`Package created successfully: ${result.outputPath}`);
756
+ return result.outputPath;
757
+ } finally {
758
+ try {
759
+ await this.fileSystem.rm(localBuildFolder);
760
+ } catch (cleanupError) {
761
+ logger?.error(`Failed to cleanup build folder: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
762
+ }
763
+ }
764
+ }
765
+ async prepareMetadataFiles(contentFolder, _contentAppFolder, _packageInfo, _manifest, projectPath) {
766
+ const mainFile = "index.html";
767
+ const mainRelativeToContent = `${CONTENT_APP_FOLDER_NAME}/${mainFile}`;
768
+ const operatePath = Path4.join(contentFolder, NugetConstants2.OperateFileName);
769
+ const operateModel = {
770
+ projectId: await ensureWebAppProjectId(this.fileSystem, projectPath),
771
+ main: mainRelativeToContent,
772
+ contentType: ProjectTypes2.WebApp,
773
+ targetFramework: TargetFramework2.Portable,
774
+ targetRuntime: TARGET_JS_RUNTIME,
775
+ runtimeOptions: {
776
+ requiresUserInteraction: false,
777
+ isAttended: false
778
+ }
779
+ };
780
+ const operateJson = JSON.stringify(operateModel, null, 2);
781
+ await this.fileSystem.writeFile(operatePath, operateJson);
782
+ const manifestSourcePath = Path4.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
783
+ const manifestDestPath = Path4.join(contentFolder, WEBAPP_MANIFEST_FILE_NAME);
784
+ const manifestExists = await this.fileSystem.exists(manifestSourcePath);
785
+ if (manifestExists) {
786
+ const manifestContent = await this.fileSystem.readFile(manifestSourcePath);
787
+ if (manifestContent) {
788
+ await this.fileSystem.writeFile(manifestDestPath, manifestContent);
789
+ }
790
+ }
791
+ const uipathJsonSourcePath = Path4.join(projectPath, "uipath.json");
792
+ const uipathJsonDestPath = Path4.join(contentFolder, "uipath.json");
793
+ const uipathJsonExists = await this.fileSystem.exists(uipathJsonSourcePath);
794
+ if (uipathJsonExists) {
795
+ const uipathJsonContent = await this.fileSystem.readFile(uipathJsonSourcePath);
796
+ if (uipathJsonContent) {
797
+ await this.fileSystem.writeFile(uipathJsonDestPath, uipathJsonContent);
798
+ }
799
+ }
800
+ const bindingsPath = Path4.join(contentFolder, "bindings.json");
801
+ const bindingsExists = await this.fileSystem.exists(bindingsPath);
802
+ if (!bindingsExists) {
803
+ const bindingsJson = JSON.stringify({ version: "1.0", resources: [] }, null, 2);
804
+ await this.fileSystem.writeFile(bindingsPath, bindingsJson);
805
+ }
806
+ const bindingsV2Path = Path4.join(contentFolder, "bindings_v2.json");
807
+ const bindingsV2Exists = await this.fileSystem.exists(bindingsV2Path);
808
+ if (!bindingsV2Exists) {
809
+ const bindingsV2Json = JSON.stringify({ version: "2.0", resources: [] }, null, 2);
810
+ await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
811
+ }
812
+ const entryPointsPath = Path4.join(contentFolder, "entry-points.json");
813
+ const projectEntryPointsPath = Path4.join(projectPath, "entry-points.json");
814
+ let entryPointsContent;
815
+ const projectEntryPointsExists = await this.fileSystem.exists(projectEntryPointsPath);
816
+ if (projectEntryPointsExists) {
817
+ const entryPointsData = await this.fileSystem.readFile(projectEntryPointsPath);
818
+ if (entryPointsData) {
819
+ entryPointsContent = new TextDecoder().decode(entryPointsData);
820
+ } else {
821
+ entryPointsContent = this.createDefaultEntryPoints(mainRelativeToContent);
822
+ }
823
+ } else {
824
+ entryPointsContent = this.createDefaultEntryPoints(mainRelativeToContent);
825
+ }
826
+ await this.fileSystem.writeFile(entryPointsPath, entryPointsContent);
827
+ const packageDescriptorPath = Path4.join(contentFolder, NugetConstants2.PackageDescriptorFileName);
828
+ const packageDescriptor = {
829
+ files: {
830
+ [NugetConstants2.OperateFileName]: Path4.join(NugetConstants2.ContentFolderName, NugetConstants2.OperateFileName),
831
+ "entry-points.json": Path4.join(NugetConstants2.ContentFolderName, "entry-points.json"),
832
+ "bindings.json": Path4.join(NugetConstants2.ContentFolderName, "bindings_v2.json")
833
+ }
834
+ };
835
+ const packageDescriptorJson = JSON.stringify(packageDescriptor, null, 2);
836
+ await this.fileSystem.writeFile(packageDescriptorPath, packageDescriptorJson);
837
+ }
838
+ createDefaultEntryPoints(mainFilePath) {
839
+ const uniqueId = this.generateUniqueId();
840
+ const entryPoints = {
841
+ $schema: "https://cloud.uipath.com/draft/2024-12/entry-point",
842
+ $id: "entry-points-doc-001",
843
+ entryPoints: [
844
+ {
845
+ filePath: mainFilePath,
846
+ uniqueId,
847
+ type: DEFAULT_ENTRY_POINT_TYPE,
848
+ input: {
849
+ amount: { type: "integer" },
850
+ id: { type: "string" }
851
+ },
852
+ output: {
853
+ status: { type: "string" }
854
+ }
855
+ }
856
+ ]
857
+ };
858
+ return JSON.stringify(entryPoints, null, 2);
859
+ }
860
+ generateUniqueId() {
861
+ const randomBytes = new Uint8Array(16);
862
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
863
+ crypto.getRandomValues(randomBytes);
864
+ } else {
865
+ throw new Error("crypto.getRandomValues is not available");
866
+ }
867
+ randomBytes[6] = randomBytes[6] & 15 | 64;
868
+ randomBytes[8] = randomBytes[8] & 63 | 128;
869
+ const hex = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
870
+ return [
871
+ hex.substring(0, 8),
872
+ hex.substring(8, 12),
873
+ hex.substring(12, 16),
874
+ hex.substring(16, 20),
875
+ hex.substring(20, 32)
876
+ ].join("-");
877
+ }
878
+ }
879
+
880
+ // src/strategies/variant-strategy-factory.ts
881
+ class VariantStrategyFactory {
882
+ static createStrategy(manifest, fileSystem) {
883
+ const variant = manifest.type;
884
+ switch (variant) {
885
+ case "Coded" /* Coded */:
886
+ return new CodedAppStrategy(fileSystem);
887
+ case "JS" /* JS */:
888
+ return new JsAppsStrategy(fileSystem);
889
+ default:
890
+ throw new Error(`Unknown WebApp variant: ${manifest.type}. Supported variants: ${Object.values(WebAppVariantType).join(", ")}`);
891
+ }
892
+ }
893
+ }
894
+
895
+ // src/webapp-tool.ts
896
+ class WebAppTool extends ProjectTool {
897
+ _temporaryStorage;
898
+ _tempBuildFolder = null;
899
+ constructor(fileSystem, logger) {
900
+ super(fileSystem, logger);
901
+ this._temporaryStorage = new TemporaryStorageService(fileSystem);
902
+ }
903
+ async restoreAsync(_options, _cancellationToken) {
904
+ this.logger.info("Restore operation is not required for WebApp projects");
905
+ return ToolResult.success();
906
+ }
907
+ async validateAsync(options, _cancellationToken) {
908
+ if (!options.projectPath) {
909
+ return this.handleError(new Error(ERROR_MESSAGES.PROJECT_PATH_REQUIRED), "Validation");
910
+ }
911
+ try {
912
+ this.logger.info("Validating WebApp project...");
913
+ let manifest;
914
+ let strategy;
915
+ try {
916
+ const prepared = await this.getManifestAndStrategy(options.projectPath);
917
+ manifest = prepared.manifest;
918
+ strategy = prepared.strategy;
919
+ } catch (error) {
920
+ return this.handleError(error, "Validation");
921
+ }
922
+ try {
923
+ if (strategy.validateAsync) {
924
+ await strategy.validateAsync({
925
+ fileSystem: this.fileSystem,
926
+ projectPath: options.projectPath,
927
+ manifest,
928
+ logger: this.createStrategyLogger()
929
+ });
930
+ }
931
+ } catch (error) {
932
+ return this.handleError(error, "Validation");
933
+ }
934
+ this.logger.info("WebApp project validation completed");
935
+ return ToolResult.success();
936
+ } catch (error) {
937
+ return this.handleError(error, "Validation");
938
+ }
939
+ }
940
+ async buildAsync(_options, _cancellationToken) {
941
+ this.logger.info("Build operation for WebApp is lightweight (metadata preparation only)");
942
+ return ToolResult.success();
943
+ }
944
+ async packAsync(options, _cancellationToken) {
945
+ if (!options.projectPath) {
946
+ return this.handleError(new Error(ERROR_MESSAGES.PROJECT_PATH_REQUIRED), "Packing");
947
+ }
948
+ if (!options.outputPath) {
949
+ return this.handleError(new Error(ERROR_MESSAGES.OUTPUT_PATH_REQUIRED), "Packing");
950
+ }
951
+ if (!options.package?.id) {
952
+ return this.handleError(new Error(ERROR_MESSAGES.PACKAGE_NAME_REQUIRED), "Packing");
953
+ }
954
+ if (!options.package?.version) {
955
+ return this.handleError(new Error(ERROR_MESSAGES.PACKAGE_VERSION_REQUIRED), "Packing");
956
+ }
957
+ try {
958
+ this.logger.info(`Packing WebApp project: ${options.package.id}@${options.package.version}`);
959
+ let manifest;
960
+ let strategy;
961
+ try {
962
+ const prepared = await this.getManifestAndStrategy(options.projectPath);
963
+ manifest = prepared.manifest;
964
+ strategy = prepared.strategy;
965
+ } catch (error) {
966
+ return this.handleError(error, `Packing WebApp project '${options.package.id}'`);
967
+ }
968
+ const nupkgPath = await strategy.packageAsync({
969
+ fileSystem: this.fileSystem,
970
+ projectPath: options.projectPath,
971
+ manifest,
972
+ outputPath: options.outputPath,
973
+ packageInfo: options.package,
974
+ logger: this.createStrategyLogger()
975
+ });
976
+ this.logger.info(`WebApp package created successfully: ${nupkgPath}`);
977
+ return new ToolResult(ToolErrorCodes.Success, "done", [nupkgPath]);
978
+ } catch (error) {
979
+ return this.handleError(error, `Packing WebApp project '${options.package.id}'`);
980
+ }
981
+ }
982
+ async dispose() {
983
+ this.logger.info("Disposing WebApp Tool");
984
+ try {
985
+ if (this._tempBuildFolder) {
986
+ await this.fileSystem.rm(this._tempBuildFolder);
987
+ this._tempBuildFolder = null;
988
+ }
989
+ await this._temporaryStorage.cleanup();
990
+ } catch {}
991
+ }
992
+ async getManifestAndStrategy(projectPath) {
993
+ const manifestPath = Path5.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
994
+ const manifestExists = await this.fileSystem.exists(manifestPath);
995
+ if (!manifestExists) {
996
+ throw new Error(ERROR_MESSAGES.MANIFEST_NOT_FOUND(WEBAPP_MANIFEST_FILE_NAME));
997
+ }
998
+ const projectJsonPath = Path5.join(projectPath, PROJECT_JSON_FILE);
999
+ if (await this.fileSystem.exists(projectJsonPath)) {
1000
+ throw new Error(ERROR_MESSAGES.PROJECT_JSON_FOUND);
1001
+ }
1002
+ const manifest = await loadWebAppManifest2(this.fileSystem, projectPath);
1003
+ if (!manifest) {
1004
+ throw new Error(ERROR_MESSAGES.MANIFEST_LOAD_FAILED(WEBAPP_MANIFEST_FILE_NAME));
1005
+ }
1006
+ const strategy = VariantStrategyFactory.createStrategy(manifest, this.fileSystem);
1007
+ return { manifest, strategy };
1008
+ }
1009
+ handleError(error, context) {
1010
+ const errorMessage = error instanceof Error ? error.message : String(error);
1011
+ this.logger.error(`${context}: ${errorMessage}`);
1012
+ let userMessage;
1013
+ if (context === "Validation") {
1014
+ userMessage = ERROR_MESSAGES.VALIDATION_FAILED(errorMessage);
1015
+ } else if (context.startsWith("Packing")) {
1016
+ userMessage = ERROR_MESSAGES.PACKING_FAILED(errorMessage);
1017
+ } else {
1018
+ userMessage = errorMessage;
1019
+ }
1020
+ return ToolResult.error(ToolErrorCodes.InternalError, userMessage);
1021
+ }
1022
+ createStrategyLogger() {
1023
+ return {
1024
+ info: (msg) => this.logger.info(msg),
1025
+ error: (msg) => this.logger.error(msg),
1026
+ progress: (msg) => this.logger.progress(msg),
1027
+ warn: (msg) => this.logger.warn(msg)
1028
+ };
1029
+ }
1030
+ }
1031
+
1032
+ // src/webapp-tool-factory.ts
1033
+ class WebAppToolFactory {
1034
+ supportedTypes = [ProjectTypes3.AppV2];
1035
+ async createAsync(logger, fileSystem) {
1036
+ return new WebAppTool(fileSystem, logger);
1037
+ }
1038
+ }
1039
+
1040
+ // src/action-schema/webapp-contributing-tool-factory.ts
1041
+ class WebAppContributingToolFactory extends WebAppToolFactory {
1042
+ async describeResourcesAsync(projectDir, fs) {
1043
+ return describeActionApp(projectDir, fs);
1044
+ }
1045
+ }
1046
+ export {
1047
+ ACTION_SCHEMA_FILE_NAME,
1048
+ JsonActionSchemaValidator,
1049
+ JsonDataType,
1050
+ JsonFormatType,
1051
+ JsonSchemaPropertySchema,
1052
+ VBDataType,
1053
+ VbArgumentCollectionType,
1054
+ VbArgumentDataTypeNamespace,
1055
+ WEBAPP_MANIFEST_FILE_NAME,
1056
+ WebAppContributingToolFactory,
1057
+ describeActionApp,
1058
+ isActionApp,
1059
+ loadWebAppManifest,
1060
+ parseActionSchema
1061
+ };
1062
+
1063
+ //# debugId=891902301953E23F64756E2164756E21
@@ -0,0 +1,45 @@
1
+ import type { IFileSystem } from "@uipath/solutionpackager-tool-core";
2
+ import { WEBAPP_MANIFEST_FILE_NAME, type WebAppManifest } from "../models/webapp-manifest.js";
3
+ /**
4
+ * Well-known file names owned by the AppV2 domain. `WEBAPP_MANIFEST_FILE_NAME`
5
+ * is re-exported from the models module so consumers of `/action-schema`
6
+ * don't need to reach into the root barrel too.
7
+ */
8
+ export declare const ACTION_SCHEMA_FILE_NAME = "action-schema.json";
9
+ export { WEBAPP_MANIFEST_FILE_NAME };
10
+ /**
11
+ * `missing` and `invalid` are kept apart on purpose: a folder with no manifest
12
+ * is a legacy coded app and packs as `Coded`, but a manifest that is there and
13
+ * cannot be read is the user's file to fix — treating it as `Coded` would
14
+ * silently turn a Coded Action back into a plain app.
15
+ */
16
+ export type WebAppManifestLoad = {
17
+ state: "missing";
18
+ } | {
19
+ state: "ok";
20
+ manifest: WebAppManifest;
21
+ } | {
22
+ state: "invalid";
23
+ reason: string;
24
+ };
25
+ /**
26
+ * Reads straight through `readFile` rather than probing with `exists()`
27
+ * first: `exists()` answers `false` for a file the process may not read, which
28
+ * would report an EACCES manifest as absent. `@uipath/filesystem` resolves a
29
+ * missing file to `null` and throws for every other failure.
30
+ */
31
+ export declare function loadWebAppManifest(fs: IFileSystem, projectDir: string): Promise<WebAppManifestLoad>;
32
+ /**
33
+ * An app is an action app when its manifest says so either way:
34
+ * `solutionResourceSubType` is the Solutions registration (what `codedapp
35
+ * push` and Studio Web read), `config.isActionApp` the packer's flag. `codedapp
36
+ * init` writes both; an older or hand-edited manifest may carry only one.
37
+ * A `null` manifest resolves to `false` so callers can compose this with a
38
+ * `missing` load without a separate branch.
39
+ */
40
+ export declare function isActionApp(manifest: WebAppManifest | null): boolean;
41
+ /**
42
+ * The `appV2_<subType>` template row this project's resources come from. A
43
+ * folder with no manifest is a legacy standalone coded app.
44
+ */
45
+ export declare function appSubTypeFor(manifest: WebAppManifest | null): string;
@@ -0,0 +1,8 @@
1
+ import { type ParsedActionSchema } from "./types.js";
2
+ /**
3
+ * Every generated `key` / `id` is derived from the property's schema path
4
+ * (not `crypto.randomUUID`) — the reconcile idempotency check and the BPMN
5
+ * bindings that pin to those keys both depend on the same input producing
6
+ * the same output. Throws on JSON / Zod / unsupported-type failures.
7
+ */
8
+ export declare function parseActionSchema(raw: string): ParsedActionSchema;
@@ -0,0 +1,94 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * AppV2 CodedAction schema types.
4
+ *
5
+ * Lives here (packager-tool-webapp) rather than in a `*-sdk` because the shape
6
+ * is one project subtype's file format — see AGENTS.md Hard Rule #19. Both
7
+ * `codedapp-tool` (cloud push) and `solution-tool`'s read-time enhancer
8
+ * wiring import from here.
9
+ *
10
+ * `ContentValidationData` names a Document Understanding contract type. It
11
+ * belongs at the layer that owns the AppV2 file format, not one below.
12
+ */
13
+ export declare enum JsonDataType {
14
+ string = "string",
15
+ integer = "integer",
16
+ number = "number",
17
+ boolean = "boolean",
18
+ array = "array",
19
+ object = "object",
20
+ file = "file",
21
+ ContentValidationData = "ContentValidationData"
22
+ }
23
+ export declare enum JsonFormatType {
24
+ uuid = "uuid",
25
+ date = "date"
26
+ }
27
+ export declare enum VbArgumentCollectionType {
28
+ array = "Array"
29
+ }
30
+ export declare enum VbArgumentDataTypeNamespace {
31
+ system = "system"
32
+ }
33
+ export declare enum VBDataType {
34
+ string = "System.String",
35
+ int64 = "System.Int64",
36
+ boolean = "System.Boolean",
37
+ decimal = "System.Decimal",
38
+ dateOnly = "System.DateOnly",
39
+ guid = "System.Guid",
40
+ object = "System.Object",
41
+ iresource = "UiPath.Platform.ResourceHandling.IResource",
42
+ ContentValidationData = "UiPath.DocumentProcessing.Contracts.Actions.ContentValidationData"
43
+ }
44
+ export type JsonSchemaProperty = {
45
+ type: JsonDataType;
46
+ required?: boolean;
47
+ description?: string;
48
+ format?: JsonFormatType;
49
+ items?: JsonSchemaProperty;
50
+ properties?: Record<string, JsonSchemaProperty>;
51
+ };
52
+ export declare const JsonSchemaPropertySchema: z.ZodType<JsonSchemaProperty>;
53
+ export declare const JsonActionSchemaValidator: z.ZodObject<{
54
+ inputs: z.ZodObject<{
55
+ type: z.ZodLiteral<"object">;
56
+ properties: z.ZodRecord<z.ZodString, z.ZodType<JsonSchemaProperty, unknown, z.core.$ZodTypeInternals<JsonSchemaProperty, unknown>>>;
57
+ }, z.core.$strip>;
58
+ outputs: z.ZodObject<{
59
+ type: z.ZodLiteral<"object">;
60
+ properties: z.ZodRecord<z.ZodString, z.ZodType<JsonSchemaProperty, unknown, z.core.$ZodTypeInternals<JsonSchemaProperty, unknown>>>;
61
+ }, z.core.$strip>;
62
+ inOuts: z.ZodObject<{
63
+ type: z.ZodLiteral<"object">;
64
+ properties: z.ZodRecord<z.ZodString, z.ZodType<JsonSchemaProperty, unknown, z.core.$ZodTypeInternals<JsonSchemaProperty, unknown>>>;
65
+ }, z.core.$strip>;
66
+ outcomes: z.ZodObject<{
67
+ type: z.ZodLiteral<"object">;
68
+ properties: z.ZodRecord<z.ZodString, z.ZodDefault<z.ZodOptional<z.ZodObject<{}, z.core.$loose>>>>;
69
+ }, z.core.$strip>;
70
+ }, z.core.$strip>;
71
+ export type JsonActionSchema = z.infer<typeof JsonActionSchemaValidator>;
72
+ export type ParsedActionPropertySchema = {
73
+ key: string;
74
+ name: string;
75
+ type: VBDataType;
76
+ isList: boolean;
77
+ typeNamespace: VbArgumentDataTypeNamespace;
78
+ version: number;
79
+ required: boolean;
80
+ properties?: ParsedActionPropertySchema[];
81
+ collectionDataType?: VbArgumentCollectionType | null;
82
+ description?: string;
83
+ };
84
+ export interface ParsedActionSchema {
85
+ id: string;
86
+ name: string;
87
+ key: string;
88
+ description: string;
89
+ inputs: ParsedActionPropertySchema[];
90
+ outputs: ParsedActionPropertySchema[];
91
+ inOuts: ParsedActionPropertySchema[];
92
+ outcomes: ParsedActionPropertySchema[];
93
+ version: number;
94
+ }
@@ -0,0 +1,17 @@
1
+ import type { IFileSystem, ProjectResourceContribution } from "@uipath/solutionpackager-tool-core";
2
+ import { WebAppToolFactory } from "../webapp-tool-factory.js";
3
+ /**
4
+ * `WebAppToolFactory` plus the AppV2 resource contribution.
5
+ *
6
+ * Lives in the node-target `./action-schema` subpath, not in the browser-built
7
+ * `.` barrel: `src/index.ts` builds `--target browser` with no `--splitting`,
8
+ * so even a lazy `import()` from there would land *in* the browser bundle
9
+ * instead of beside it. `codedapp-tool/src/packager-tool.ts` is node-only and
10
+ * registers this subclass; the browser entry keeps the plain factory.
11
+ *
12
+ * `supportedTypes` is inherited unchanged — `ToolsFactoryRepository` keys
13
+ * dispatch on it, and the first factory registered for a type wins.
14
+ */
15
+ export declare class WebAppContributingToolFactory extends WebAppToolFactory {
16
+ describeResourcesAsync(projectDir: string, fs: IFileSystem): Promise<ProjectResourceContribution>;
17
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@uipath/packager-tool-webapp",
3
- "version": "1.202.0-preview.159",
3
+ "version": "1.203.0-preview.160",
4
4
  "description": "UiPath WebApp tool implementation",
5
5
  "type": "module",
6
6
  "exports": {
7
- ".": "./dist/index.js"
7
+ ".": "./dist/index.js",
8
+ "./action-schema": "./dist/action-schema/index.js"
8
9
  },
9
10
  "repository": {
10
11
  "type": "git",
@@ -18,10 +19,12 @@
18
19
  "files": [
19
20
  "dist"
20
21
  ],
21
- "author": "",
22
+ "author": "UiPath",
22
23
  "license": "SEE LICENSE IN LICENSE.txt",
23
24
  "peerDependencies": {
24
- "@uipath/solutionpackager-tool-core": "1.202.0"
25
+ "@uipath/common": "1.203.0",
26
+ "@uipath/solutionpackager-tool-core": "1.203.0",
27
+ "zod": "^4.3.6"
25
28
  },
26
- "gitHead": "a3f23209784c6cec7155e735fa051b48ca49e8d7"
29
+ "gitHead": "3a42062ba731afca4595ba9aa8a80afc9667528d"
27
30
  }