@uipath/packager-tool-webapp 1.0.5 → 1.197.0-preview.64
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/constants.d.ts +14 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +295 -78
- package/dist/models/webapp-manifest.d.ts +1 -0
- package/dist/strategies/js-apps-strategy.d.ts +40 -0
- package/dist/utils/manifest-loader.d.ts +5 -0
- package/package.json +29 -57
- package/src/constants.ts +21 -0
- package/src/index.ts +7 -5
- package/src/models/webapp-manifest.ts +1 -0
- package/src/strategies/coded-app-strategy.ts +44 -11
- package/src/strategies/js-apps-strategy.ts +378 -0
- package/src/strategies/variant-strategy-factory.ts +2 -3
- package/src/utils/manifest-loader.ts +29 -0
package/dist/constants.d.ts
CHANGED
|
@@ -9,10 +9,22 @@ export declare const PROJECT_JSON_FILE = "project.json";
|
|
|
9
9
|
* Default bundle path if not specified in manifest
|
|
10
10
|
*/
|
|
11
11
|
export declare const DEFAULT_BUNDLE_PATH = "source/dist";
|
|
12
|
+
/**
|
|
13
|
+
* Pre-built app folder for the JS variant (source)
|
|
14
|
+
*/
|
|
15
|
+
export declare const APP_FOLDER_NAME = ".app";
|
|
16
|
+
/**
|
|
17
|
+
* Destination folder inside the NuGet content folder for the JS variant
|
|
18
|
+
*/
|
|
19
|
+
export declare const CONTENT_APP_FOLDER_NAME = "app";
|
|
12
20
|
/**
|
|
13
21
|
* Target runtime for operate.json
|
|
14
22
|
*/
|
|
15
23
|
export declare const TARGET_RUNTIME = "Coded";
|
|
24
|
+
/**
|
|
25
|
+
* Target runtime for operate.json
|
|
26
|
+
*/
|
|
27
|
+
export declare const TARGET_JS_RUNTIME = "JS";
|
|
16
28
|
/**
|
|
17
29
|
* Default entry point type
|
|
18
30
|
*/
|
|
@@ -26,6 +38,8 @@ export declare const ERROR_MESSAGES: {
|
|
|
26
38
|
readonly MANIFEST_LOAD_FAILED: (file: string) => string;
|
|
27
39
|
readonly BUNDLE_NOT_FOUND: (path: string) => string;
|
|
28
40
|
readonly BUNDLE_NOT_DIRECTORY: (path: string) => string;
|
|
41
|
+
readonly APP_FOLDER_NOT_FOUND: (path: string) => string;
|
|
42
|
+
readonly APP_FOLDER_NOT_DIRECTORY: (path: string) => string;
|
|
29
43
|
readonly BUILD_NOT_SUPPORTED: "Build execution (isCompiled=false) is not yet supported. Please build the project manually and set isCompiled=true.";
|
|
30
44
|
readonly VALIDATION_FAILED: (context: string) => string;
|
|
31
45
|
readonly PACKING_FAILED: (context: string) => string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
export type { WebAppManifest } from "./models/webapp-manifest.js";
|
|
2
|
+
export { WEBAPP_MANIFEST_FILE_NAME, WebAppVariantType, } from "./models/webapp-manifest.js";
|
|
1
3
|
export { WebAppTool } from "./webapp-tool.js";
|
|
2
4
|
export { WebAppToolFactory } from "./webapp-tool-factory.js";
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
// src/models/webapp-manifest.ts
|
|
2
|
+
var WebAppVariantType;
|
|
3
|
+
((WebAppVariantType2) => {
|
|
4
|
+
WebAppVariantType2["Coded"] = "Coded";
|
|
5
|
+
WebAppVariantType2["JS"] = "JS";
|
|
6
|
+
})(WebAppVariantType ||= {});
|
|
7
|
+
var WEBAPP_MANIFEST_FILE_NAME = "webAppManifest.json";
|
|
9
8
|
// src/webapp-tool.ts
|
|
10
9
|
import {
|
|
11
|
-
Path as
|
|
10
|
+
Path as Path5,
|
|
12
11
|
ProjectTool,
|
|
13
12
|
TemporaryStorageService,
|
|
14
13
|
ToolErrorCodes,
|
|
@@ -18,7 +17,10 @@ import {
|
|
|
18
17
|
// src/constants.ts
|
|
19
18
|
var PROJECT_JSON_FILE = "project.json";
|
|
20
19
|
var DEFAULT_BUNDLE_PATH = "source/dist";
|
|
20
|
+
var APP_FOLDER_NAME = ".app";
|
|
21
|
+
var CONTENT_APP_FOLDER_NAME = "app";
|
|
21
22
|
var TARGET_RUNTIME = "Coded";
|
|
23
|
+
var TARGET_JS_RUNTIME = "JS";
|
|
22
24
|
var DEFAULT_ENTRY_POINT_TYPE = "api";
|
|
23
25
|
var ERROR_MESSAGES = {
|
|
24
26
|
MANIFEST_NOT_FOUND: (file) => `WebApp manifest not found: ${file}. This file is required for WebApp projects.`,
|
|
@@ -26,6 +28,8 @@ var ERROR_MESSAGES = {
|
|
|
26
28
|
MANIFEST_LOAD_FAILED: (file) => `Failed to load or parse ${file}`,
|
|
27
29
|
BUNDLE_NOT_FOUND: (path) => `Compiled bundle not found at ${path}. Ensure the project is built before packing.`,
|
|
28
30
|
BUNDLE_NOT_DIRECTORY: (path) => `Bundle path ${path} exists but is not a directory.`,
|
|
31
|
+
APP_FOLDER_NOT_FOUND: (path) => `.app folder not found at ${path}. Ensure the project contains a .app folder.`,
|
|
32
|
+
APP_FOLDER_NOT_DIRECTORY: (path) => `.app path ${path} exists but is not a directory.`,
|
|
29
33
|
BUILD_NOT_SUPPORTED: "Build execution (isCompiled=false) is not yet supported. Please build the project manually and set isCompiled=true.",
|
|
30
34
|
VALIDATION_FAILED: (context) => `Validation failed: ${context}`,
|
|
31
35
|
PACKING_FAILED: (context) => `An error occurred while packing WebApp project: ${context}`,
|
|
@@ -35,19 +39,11 @@ var ERROR_MESSAGES = {
|
|
|
35
39
|
OUTPUT_PATH_REQUIRED: "Output path is required"
|
|
36
40
|
};
|
|
37
41
|
|
|
38
|
-
// src/models/webapp-manifest.ts
|
|
39
|
-
var WebAppVariantType;
|
|
40
|
-
((WebAppVariantType2) => {
|
|
41
|
-
WebAppVariantType2["Coded"] = "Coded";
|
|
42
|
-
WebAppVariantType2["JS"] = "JS";
|
|
43
|
-
})(WebAppVariantType ||= {});
|
|
44
|
-
var WEBAPP_MANIFEST_FILE_NAME = "webAppManifest.json";
|
|
45
|
-
|
|
46
42
|
// src/strategies/coded-app-strategy.ts
|
|
47
43
|
import {
|
|
48
44
|
NugetConstants,
|
|
49
45
|
NugetPackager,
|
|
50
|
-
Path as
|
|
46
|
+
Path as Path3,
|
|
51
47
|
ProjectTypes,
|
|
52
48
|
TargetFramework
|
|
53
49
|
} from "@uipath/solutionpackager-tool-core";
|
|
@@ -72,6 +68,41 @@ async function copyDirectoryAsync(fileSystem, sourcePath, destinationPath) {
|
|
|
72
68
|
}
|
|
73
69
|
}
|
|
74
70
|
|
|
71
|
+
// src/utils/manifest-loader.ts
|
|
72
|
+
import { Path as Path2 } from "@uipath/solutionpackager-tool-core";
|
|
73
|
+
async function loadWebAppManifest(fileSystem, projectPath) {
|
|
74
|
+
const manifestPath = Path2.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
75
|
+
const exists = await fileSystem.exists(manifestPath);
|
|
76
|
+
if (!exists) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const content = await fileSystem.readFile(manifestPath);
|
|
80
|
+
if (!content) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const text = new TextDecoder().decode(content);
|
|
85
|
+
const manifest = JSON.parse(text);
|
|
86
|
+
return manifest;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
throw new Error(`Failed to parse ${WEBAPP_MANIFEST_FILE_NAME}: ${error instanceof Error ? error.message : String(error)}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function ensureWebAppProjectId(fileSystem, projectPath) {
|
|
92
|
+
const manifest = await loadWebAppManifest(fileSystem, projectPath);
|
|
93
|
+
if (manifest && typeof manifest.projectId === "string" && manifest.projectId.length > 0) {
|
|
94
|
+
return manifest.projectId;
|
|
95
|
+
}
|
|
96
|
+
const id = crypto.randomUUID();
|
|
97
|
+
if (manifest) {
|
|
98
|
+
const updated = { ...manifest, projectId: id };
|
|
99
|
+
const manifestPath = Path2.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
100
|
+
await fileSystem.writeFile(manifestPath, `${JSON.stringify(updated, null, 2)}
|
|
101
|
+
`);
|
|
102
|
+
}
|
|
103
|
+
return id;
|
|
104
|
+
}
|
|
105
|
+
|
|
75
106
|
// src/strategies/coded-app-strategy.ts
|
|
76
107
|
class CodedAppStrategy {
|
|
77
108
|
fileSystem;
|
|
@@ -87,7 +118,7 @@ class CodedAppStrategy {
|
|
|
87
118
|
}
|
|
88
119
|
const isCompiled = typed.config?.isCompiled ?? true;
|
|
89
120
|
if (isCompiled) {
|
|
90
|
-
const fullBundlePath =
|
|
121
|
+
const fullBundlePath = Path3.join(projectPath, bundlePath);
|
|
91
122
|
const exists = await this.fileSystem.exists(fullBundlePath);
|
|
92
123
|
if (!exists) {
|
|
93
124
|
const message = ERROR_MESSAGES.BUNDLE_NOT_FOUND(fullBundlePath);
|
|
@@ -107,7 +138,7 @@ class CodedAppStrategy {
|
|
|
107
138
|
bundlePath = DEFAULT_BUNDLE_PATH;
|
|
108
139
|
}
|
|
109
140
|
const isCompiled = manifest.config?.isCompiled ?? true;
|
|
110
|
-
const fullBundlePath =
|
|
141
|
+
const fullBundlePath = Path3.join(projectPath, bundlePath);
|
|
111
142
|
if (isCompiled) {
|
|
112
143
|
logger?.progress("Validating compiled bundle...");
|
|
113
144
|
const bundleExists = await this.fileSystem.exists(fullBundlePath);
|
|
@@ -122,8 +153,8 @@ class CodedAppStrategy {
|
|
|
122
153
|
logger?.info("Build mode (isCompiled=false) is not yet implemented in v1.");
|
|
123
154
|
throw new Error(ERROR_MESSAGES.BUILD_NOT_SUPPORTED);
|
|
124
155
|
}
|
|
125
|
-
const localBuildFolder =
|
|
126
|
-
const contentFolder =
|
|
156
|
+
const localBuildFolder = Path3.join(outputPath, NugetConstants.OutputFolderName);
|
|
157
|
+
const contentFolder = Path3.join(localBuildFolder, NugetConstants.ContentFolderName);
|
|
127
158
|
await this.fileSystem.mkdir(contentFolder);
|
|
128
159
|
try {
|
|
129
160
|
logger?.progress("Copying bundle to content folder...");
|
|
@@ -132,7 +163,7 @@ class CodedAppStrategy {
|
|
|
132
163
|
await this.prepareMetadataFiles(localBuildFolder, contentFolder, packageInfo, manifest, projectPath);
|
|
133
164
|
logger?.progress("Creating NuGet package...");
|
|
134
165
|
const nupkgFileName = `${packageInfo.id}.${packageInfo.version}.nupkg`;
|
|
135
|
-
const nupkgPath =
|
|
166
|
+
const nupkgPath = Path3.join(outputPath, nupkgFileName);
|
|
136
167
|
const packager = new NugetPackager(this.fileSystem);
|
|
137
168
|
const result = await packager.packAsync(localBuildFolder, packageInfo, nupkgPath);
|
|
138
169
|
logger?.info(`Package created successfully: ${result.outputPath}`);
|
|
@@ -145,23 +176,23 @@ class CodedAppStrategy {
|
|
|
145
176
|
}
|
|
146
177
|
}
|
|
147
178
|
}
|
|
148
|
-
async prepareMetadataFiles(_localBuildFolder, contentFolder,
|
|
179
|
+
async prepareMetadataFiles(_localBuildFolder, contentFolder, _packageInfo, _manifest, projectPath) {
|
|
149
180
|
let mainFile = "index.html";
|
|
150
|
-
const indexHtmlPath =
|
|
181
|
+
const indexHtmlPath = Path3.join(contentFolder, "index.html");
|
|
151
182
|
const indexHtmlExists = await this.fileSystem.exists(indexHtmlPath);
|
|
152
183
|
if (!indexHtmlExists) {
|
|
153
184
|
const possibleEntries = ["index.html", "main.html", "app.html"];
|
|
154
185
|
for (const entry of possibleEntries) {
|
|
155
|
-
const entryPath =
|
|
186
|
+
const entryPath = Path3.join(contentFolder, entry);
|
|
156
187
|
if (await this.fileSystem.exists(entryPath)) {
|
|
157
188
|
mainFile = entry;
|
|
158
189
|
break;
|
|
159
190
|
}
|
|
160
191
|
}
|
|
161
192
|
}
|
|
162
|
-
const operatePath =
|
|
193
|
+
const operatePath = Path3.join(contentFolder, NugetConstants.OperateFileName);
|
|
163
194
|
const operateModel = {
|
|
164
|
-
projectId:
|
|
195
|
+
projectId: await ensureWebAppProjectId(this.fileSystem, projectPath),
|
|
165
196
|
main: mainFile,
|
|
166
197
|
contentType: ProjectTypes.WebApp,
|
|
167
198
|
targetFramework: TargetFramework.Portable,
|
|
@@ -173,25 +204,25 @@ class CodedAppStrategy {
|
|
|
173
204
|
};
|
|
174
205
|
const operateJson = JSON.stringify(operateModel, null, 2);
|
|
175
206
|
await this.fileSystem.writeFile(operatePath, operateJson);
|
|
176
|
-
const manifestSourcePath =
|
|
177
|
-
const manifestDestPath =
|
|
207
|
+
const manifestSourcePath = Path3.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
208
|
+
const manifestDestPath = Path3.join(contentFolder, WEBAPP_MANIFEST_FILE_NAME);
|
|
178
209
|
const manifestExists = await this.fileSystem.exists(manifestSourcePath);
|
|
179
210
|
if (manifestExists) {
|
|
180
|
-
const manifestContent = await this.fileSystem.readFile(manifestSourcePath);
|
|
211
|
+
const manifestContent = await this.fileSystem.readFile(manifestSourcePath, "utf-8");
|
|
181
212
|
if (manifestContent) {
|
|
182
213
|
await this.fileSystem.writeFile(manifestDestPath, manifestContent);
|
|
183
214
|
}
|
|
184
215
|
}
|
|
185
|
-
const uipathJsonSourcePath =
|
|
186
|
-
const uipathJsonDestPath =
|
|
216
|
+
const uipathJsonSourcePath = Path3.join(projectPath, "uipath.json");
|
|
217
|
+
const uipathJsonDestPath = Path3.join(contentFolder, "uipath.json");
|
|
187
218
|
const uipathJsonExists = await this.fileSystem.exists(uipathJsonSourcePath);
|
|
188
219
|
if (uipathJsonExists) {
|
|
189
|
-
const uipathJsonContent = await this.fileSystem.readFile(uipathJsonSourcePath);
|
|
220
|
+
const uipathJsonContent = await this.fileSystem.readFile(uipathJsonSourcePath, "utf-8");
|
|
190
221
|
if (uipathJsonContent) {
|
|
191
222
|
await this.fileSystem.writeFile(uipathJsonDestPath, uipathJsonContent);
|
|
192
223
|
}
|
|
193
224
|
}
|
|
194
|
-
const bindingsPath =
|
|
225
|
+
const bindingsPath = Path3.join(contentFolder, "bindings.json");
|
|
195
226
|
const bindingsExists = await this.fileSystem.exists(bindingsPath);
|
|
196
227
|
if (!bindingsExists) {
|
|
197
228
|
const bindingsJson = JSON.stringify({
|
|
@@ -200,23 +231,38 @@ class CodedAppStrategy {
|
|
|
200
231
|
}, null, 2);
|
|
201
232
|
await this.fileSystem.writeFile(bindingsPath, bindingsJson);
|
|
202
233
|
}
|
|
203
|
-
const bindingsV2Path =
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
234
|
+
const bindingsV2Path = Path3.join(contentFolder, "bindings_v2.json");
|
|
235
|
+
const bindingsCandidatePaths = [
|
|
236
|
+
Path3.join(projectPath, "source", "bindings.json"),
|
|
237
|
+
Path3.join(projectPath, "bindings.json"),
|
|
238
|
+
Path3.join(projectPath, "bindings_v2.json")
|
|
239
|
+
];
|
|
240
|
+
let bindingsV2Json = null;
|
|
241
|
+
for (const candidate of bindingsCandidatePaths) {
|
|
242
|
+
if (await this.fileSystem.exists(candidate)) {
|
|
243
|
+
bindingsV2Json = await this.fileSystem.readFile(candidate, "utf-8");
|
|
244
|
+
if (bindingsV2Json)
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (!bindingsV2Json && await this.fileSystem.exists(bindingsV2Path)) {
|
|
249
|
+
bindingsV2Json = await this.fileSystem.readFile(bindingsV2Path, "utf-8");
|
|
250
|
+
}
|
|
251
|
+
if (!bindingsV2Json) {
|
|
252
|
+
bindingsV2Json = JSON.stringify({
|
|
207
253
|
version: "2.0",
|
|
208
254
|
resources: []
|
|
209
255
|
}, null, 2);
|
|
210
|
-
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
211
256
|
}
|
|
212
|
-
|
|
213
|
-
const
|
|
257
|
+
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
258
|
+
const entryPointsPath = Path3.join(contentFolder, "entry-points.json");
|
|
259
|
+
const projectEntryPointsPath = Path3.join(projectPath, "entry-points.json");
|
|
214
260
|
let entryPointsContent;
|
|
215
261
|
const projectEntryPointsExists = await this.fileSystem.exists(projectEntryPointsPath);
|
|
216
262
|
if (projectEntryPointsExists) {
|
|
217
|
-
const entryPointsData = await this.fileSystem.readFile(projectEntryPointsPath);
|
|
263
|
+
const entryPointsData = await this.fileSystem.readFile(projectEntryPointsPath, "utf-8");
|
|
218
264
|
if (entryPointsData) {
|
|
219
|
-
entryPointsContent =
|
|
265
|
+
entryPointsContent = entryPointsData;
|
|
220
266
|
} else {
|
|
221
267
|
entryPointsContent = this.createDefaultEntryPoints(mainFile);
|
|
222
268
|
}
|
|
@@ -224,12 +270,13 @@ class CodedAppStrategy {
|
|
|
224
270
|
entryPointsContent = this.createDefaultEntryPoints(mainFile);
|
|
225
271
|
}
|
|
226
272
|
await this.fileSystem.writeFile(entryPointsPath, entryPointsContent);
|
|
227
|
-
const packageDescriptorPath =
|
|
273
|
+
const packageDescriptorPath = Path3.join(contentFolder, NugetConstants.PackageDescriptorFileName);
|
|
228
274
|
const packageDescriptor = {
|
|
275
|
+
$schema: "https://cloud.uipath.com/draft/2024-12/package-descriptor",
|
|
229
276
|
files: {
|
|
230
|
-
[NugetConstants.OperateFileName]:
|
|
231
|
-
"entry-points.json":
|
|
232
|
-
"bindings.json":
|
|
277
|
+
[NugetConstants.OperateFileName]: Path3.join(NugetConstants.ContentFolderName, NugetConstants.OperateFileName),
|
|
278
|
+
"entry-points.json": Path3.join(NugetConstants.ContentFolderName, "entry-points.json"),
|
|
279
|
+
"bindings.json": Path3.join(NugetConstants.ContentFolderName, "bindings_v2.json")
|
|
233
280
|
}
|
|
234
281
|
};
|
|
235
282
|
const packageDescriptorJson = JSON.stringify(packageDescriptor, null, 2);
|
|
@@ -277,6 +324,194 @@ class CodedAppStrategy {
|
|
|
277
324
|
}
|
|
278
325
|
}
|
|
279
326
|
|
|
327
|
+
// src/strategies/js-apps-strategy.ts
|
|
328
|
+
import {
|
|
329
|
+
NugetConstants as NugetConstants2,
|
|
330
|
+
NugetPackager as NugetPackager2,
|
|
331
|
+
Path as Path4,
|
|
332
|
+
ProjectTypes as ProjectTypes2,
|
|
333
|
+
TargetFramework as TargetFramework2
|
|
334
|
+
} from "@uipath/solutionpackager-tool-core";
|
|
335
|
+
class JsAppsStrategy {
|
|
336
|
+
fileSystem;
|
|
337
|
+
constructor(fileSystem) {
|
|
338
|
+
this.fileSystem = fileSystem;
|
|
339
|
+
}
|
|
340
|
+
async validateAsync(args) {
|
|
341
|
+
const { projectPath, logger } = args;
|
|
342
|
+
const appFolder = Path4.join(projectPath, APP_FOLDER_NAME);
|
|
343
|
+
const exists = await this.fileSystem.exists(appFolder);
|
|
344
|
+
if (!exists) {
|
|
345
|
+
const message = ERROR_MESSAGES.APP_FOLDER_NOT_FOUND(appFolder);
|
|
346
|
+
if (logger?.warn) {
|
|
347
|
+
logger.warn(message);
|
|
348
|
+
} else {
|
|
349
|
+
logger?.info(`Warning: ${message}`);
|
|
350
|
+
}
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const stat = await this.fileSystem.stat(appFolder);
|
|
354
|
+
if (!stat?.isDirectory()) {
|
|
355
|
+
const message = ERROR_MESSAGES.APP_FOLDER_NOT_DIRECTORY(appFolder);
|
|
356
|
+
if (logger?.warn) {
|
|
357
|
+
logger.warn(message);
|
|
358
|
+
} else {
|
|
359
|
+
logger?.info(`Warning: ${message}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async packageAsync(args) {
|
|
364
|
+
const { projectPath, manifest, outputPath, packageInfo, logger } = args;
|
|
365
|
+
logger?.info(`Packaging JS variant: ${packageInfo.id}@${packageInfo.version}`);
|
|
366
|
+
const appFolder = Path4.join(projectPath, APP_FOLDER_NAME);
|
|
367
|
+
logger?.progress("Validating .app folder...");
|
|
368
|
+
const appFolderExists = await this.fileSystem.exists(appFolder);
|
|
369
|
+
if (!appFolderExists) {
|
|
370
|
+
throw new Error(ERROR_MESSAGES.APP_FOLDER_NOT_FOUND(appFolder));
|
|
371
|
+
}
|
|
372
|
+
const appFolderStat = await this.fileSystem.stat(appFolder);
|
|
373
|
+
if (!appFolderStat?.isDirectory()) {
|
|
374
|
+
throw new Error(ERROR_MESSAGES.APP_FOLDER_NOT_DIRECTORY(appFolder));
|
|
375
|
+
}
|
|
376
|
+
const localBuildFolder = Path4.join(outputPath, NugetConstants2.OutputFolderName);
|
|
377
|
+
const contentFolder = Path4.join(localBuildFolder, NugetConstants2.ContentFolderName);
|
|
378
|
+
const contentAppFolder = Path4.join(contentFolder, CONTENT_APP_FOLDER_NAME);
|
|
379
|
+
await this.fileSystem.mkdir(contentFolder);
|
|
380
|
+
try {
|
|
381
|
+
logger?.progress("Copying .app folder into content/app...");
|
|
382
|
+
await copyDirectoryAsync(this.fileSystem, appFolder, contentAppFolder);
|
|
383
|
+
logger?.progress("Preparing metadata files...");
|
|
384
|
+
await this.prepareMetadataFiles(contentFolder, contentAppFolder, packageInfo, manifest, projectPath);
|
|
385
|
+
logger?.progress("Creating NuGet package...");
|
|
386
|
+
const nupkgFileName = `${packageInfo.id}.${packageInfo.version}.nupkg`;
|
|
387
|
+
const nupkgPath = Path4.join(outputPath, nupkgFileName);
|
|
388
|
+
const packager = new NugetPackager2(this.fileSystem);
|
|
389
|
+
const result = await packager.packAsync(localBuildFolder, packageInfo, nupkgPath);
|
|
390
|
+
logger?.info(`Package created successfully: ${result.outputPath}`);
|
|
391
|
+
return result.outputPath;
|
|
392
|
+
} finally {
|
|
393
|
+
try {
|
|
394
|
+
await this.fileSystem.rm(localBuildFolder);
|
|
395
|
+
} catch (cleanupError) {
|
|
396
|
+
logger?.error(`Failed to cleanup build folder: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async prepareMetadataFiles(contentFolder, _contentAppFolder, _packageInfo, _manifest, projectPath) {
|
|
401
|
+
const mainFile = "index.html";
|
|
402
|
+
const mainRelativeToContent = `${CONTENT_APP_FOLDER_NAME}/${mainFile}`;
|
|
403
|
+
const operatePath = Path4.join(contentFolder, NugetConstants2.OperateFileName);
|
|
404
|
+
const operateModel = {
|
|
405
|
+
projectId: await ensureWebAppProjectId(this.fileSystem, projectPath),
|
|
406
|
+
main: mainRelativeToContent,
|
|
407
|
+
contentType: ProjectTypes2.WebApp,
|
|
408
|
+
targetFramework: TargetFramework2.Portable,
|
|
409
|
+
targetRuntime: TARGET_JS_RUNTIME,
|
|
410
|
+
runtimeOptions: {
|
|
411
|
+
requiresUserInteraction: false,
|
|
412
|
+
isAttended: false
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
const operateJson = JSON.stringify(operateModel, null, 2);
|
|
416
|
+
await this.fileSystem.writeFile(operatePath, operateJson);
|
|
417
|
+
const manifestSourcePath = Path4.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
418
|
+
const manifestDestPath = Path4.join(contentFolder, WEBAPP_MANIFEST_FILE_NAME);
|
|
419
|
+
const manifestExists = await this.fileSystem.exists(manifestSourcePath);
|
|
420
|
+
if (manifestExists) {
|
|
421
|
+
const manifestContent = await this.fileSystem.readFile(manifestSourcePath);
|
|
422
|
+
if (manifestContent) {
|
|
423
|
+
await this.fileSystem.writeFile(manifestDestPath, manifestContent);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const uipathJsonSourcePath = Path4.join(projectPath, "uipath.json");
|
|
427
|
+
const uipathJsonDestPath = Path4.join(contentFolder, "uipath.json");
|
|
428
|
+
const uipathJsonExists = await this.fileSystem.exists(uipathJsonSourcePath);
|
|
429
|
+
if (uipathJsonExists) {
|
|
430
|
+
const uipathJsonContent = await this.fileSystem.readFile(uipathJsonSourcePath);
|
|
431
|
+
if (uipathJsonContent) {
|
|
432
|
+
await this.fileSystem.writeFile(uipathJsonDestPath, uipathJsonContent);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const bindingsPath = Path4.join(contentFolder, "bindings.json");
|
|
436
|
+
const bindingsExists = await this.fileSystem.exists(bindingsPath);
|
|
437
|
+
if (!bindingsExists) {
|
|
438
|
+
const bindingsJson = JSON.stringify({ version: "1.0", resources: [] }, null, 2);
|
|
439
|
+
await this.fileSystem.writeFile(bindingsPath, bindingsJson);
|
|
440
|
+
}
|
|
441
|
+
const bindingsV2Path = Path4.join(contentFolder, "bindings_v2.json");
|
|
442
|
+
const bindingsV2Exists = await this.fileSystem.exists(bindingsV2Path);
|
|
443
|
+
if (!bindingsV2Exists) {
|
|
444
|
+
const bindingsV2Json = JSON.stringify({ version: "2.0", resources: [] }, null, 2);
|
|
445
|
+
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
446
|
+
}
|
|
447
|
+
const entryPointsPath = Path4.join(contentFolder, "entry-points.json");
|
|
448
|
+
const projectEntryPointsPath = Path4.join(projectPath, "entry-points.json");
|
|
449
|
+
let entryPointsContent;
|
|
450
|
+
const projectEntryPointsExists = await this.fileSystem.exists(projectEntryPointsPath);
|
|
451
|
+
if (projectEntryPointsExists) {
|
|
452
|
+
const entryPointsData = await this.fileSystem.readFile(projectEntryPointsPath);
|
|
453
|
+
if (entryPointsData) {
|
|
454
|
+
entryPointsContent = new TextDecoder().decode(entryPointsData);
|
|
455
|
+
} else {
|
|
456
|
+
entryPointsContent = this.createDefaultEntryPoints(mainRelativeToContent);
|
|
457
|
+
}
|
|
458
|
+
} else {
|
|
459
|
+
entryPointsContent = this.createDefaultEntryPoints(mainRelativeToContent);
|
|
460
|
+
}
|
|
461
|
+
await this.fileSystem.writeFile(entryPointsPath, entryPointsContent);
|
|
462
|
+
const packageDescriptorPath = Path4.join(contentFolder, NugetConstants2.PackageDescriptorFileName);
|
|
463
|
+
const packageDescriptor = {
|
|
464
|
+
files: {
|
|
465
|
+
[NugetConstants2.OperateFileName]: Path4.join(NugetConstants2.ContentFolderName, NugetConstants2.OperateFileName),
|
|
466
|
+
"entry-points.json": Path4.join(NugetConstants2.ContentFolderName, "entry-points.json"),
|
|
467
|
+
"bindings.json": Path4.join(NugetConstants2.ContentFolderName, "bindings_v2.json")
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
const packageDescriptorJson = JSON.stringify(packageDescriptor, null, 2);
|
|
471
|
+
await this.fileSystem.writeFile(packageDescriptorPath, packageDescriptorJson);
|
|
472
|
+
}
|
|
473
|
+
createDefaultEntryPoints(mainFilePath) {
|
|
474
|
+
const uniqueId = this.generateUniqueId();
|
|
475
|
+
const entryPoints = {
|
|
476
|
+
$schema: "https://cloud.uipath.com/draft/2024-12/entry-point",
|
|
477
|
+
$id: "entry-points-doc-001",
|
|
478
|
+
entryPoints: [
|
|
479
|
+
{
|
|
480
|
+
filePath: mainFilePath,
|
|
481
|
+
uniqueId,
|
|
482
|
+
type: DEFAULT_ENTRY_POINT_TYPE,
|
|
483
|
+
input: {
|
|
484
|
+
amount: { type: "integer" },
|
|
485
|
+
id: { type: "string" }
|
|
486
|
+
},
|
|
487
|
+
output: {
|
|
488
|
+
status: { type: "string" }
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
]
|
|
492
|
+
};
|
|
493
|
+
return JSON.stringify(entryPoints, null, 2);
|
|
494
|
+
}
|
|
495
|
+
generateUniqueId() {
|
|
496
|
+
const randomBytes = new Uint8Array(16);
|
|
497
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
498
|
+
crypto.getRandomValues(randomBytes);
|
|
499
|
+
} else {
|
|
500
|
+
throw new Error("crypto.getRandomValues is not available");
|
|
501
|
+
}
|
|
502
|
+
randomBytes[6] = randomBytes[6] & 15 | 64;
|
|
503
|
+
randomBytes[8] = randomBytes[8] & 63 | 128;
|
|
504
|
+
const hex = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
505
|
+
return [
|
|
506
|
+
hex.substring(0, 8),
|
|
507
|
+
hex.substring(8, 12),
|
|
508
|
+
hex.substring(12, 16),
|
|
509
|
+
hex.substring(16, 20),
|
|
510
|
+
hex.substring(20, 32)
|
|
511
|
+
].join("-");
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
280
515
|
// src/strategies/variant-strategy-factory.ts
|
|
281
516
|
class VariantStrategyFactory {
|
|
282
517
|
static createStrategy(manifest, fileSystem) {
|
|
@@ -285,34 +520,13 @@ class VariantStrategyFactory {
|
|
|
285
520
|
case "Coded" /* Coded */:
|
|
286
521
|
return new CodedAppStrategy(fileSystem);
|
|
287
522
|
case "JS" /* JS */:
|
|
288
|
-
|
|
523
|
+
return new JsAppsStrategy(fileSystem);
|
|
289
524
|
default:
|
|
290
525
|
throw new Error(`Unknown WebApp variant: ${manifest.type}. Supported variants: ${Object.values(WebAppVariantType).join(", ")}`);
|
|
291
526
|
}
|
|
292
527
|
}
|
|
293
528
|
}
|
|
294
529
|
|
|
295
|
-
// src/utils/manifest-loader.ts
|
|
296
|
-
import { Path as Path3 } from "@uipath/solutionpackager-tool-core";
|
|
297
|
-
async function loadWebAppManifest(fileSystem, projectPath) {
|
|
298
|
-
const manifestPath = Path3.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
299
|
-
const exists = await fileSystem.exists(manifestPath);
|
|
300
|
-
if (!exists) {
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
const content = await fileSystem.readFile(manifestPath);
|
|
304
|
-
if (!content) {
|
|
305
|
-
return null;
|
|
306
|
-
}
|
|
307
|
-
try {
|
|
308
|
-
const text = new TextDecoder().decode(content);
|
|
309
|
-
const manifest = JSON.parse(text);
|
|
310
|
-
return manifest;
|
|
311
|
-
} catch (error) {
|
|
312
|
-
throw new Error(`Failed to parse ${WEBAPP_MANIFEST_FILE_NAME}: ${error instanceof Error ? error.message : String(error)}`);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
530
|
// src/webapp-tool.ts
|
|
317
531
|
class WebAppTool extends ProjectTool {
|
|
318
532
|
_temporaryStorage;
|
|
@@ -411,12 +625,12 @@ class WebAppTool extends ProjectTool {
|
|
|
411
625
|
} catch {}
|
|
412
626
|
}
|
|
413
627
|
async getManifestAndStrategy(projectPath) {
|
|
414
|
-
const manifestPath =
|
|
628
|
+
const manifestPath = Path5.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
415
629
|
const manifestExists = await this.fileSystem.exists(manifestPath);
|
|
416
630
|
if (!manifestExists) {
|
|
417
631
|
throw new Error(ERROR_MESSAGES.MANIFEST_NOT_FOUND(WEBAPP_MANIFEST_FILE_NAME));
|
|
418
632
|
}
|
|
419
|
-
const projectJsonPath =
|
|
633
|
+
const projectJsonPath = Path5.join(projectPath, PROJECT_JSON_FILE);
|
|
420
634
|
if (await this.fileSystem.exists(projectJsonPath)) {
|
|
421
635
|
throw new Error(ERROR_MESSAGES.PROJECT_JSON_FOUND);
|
|
422
636
|
}
|
|
@@ -449,18 +663,21 @@ class WebAppTool extends ProjectTool {
|
|
|
449
663
|
};
|
|
450
664
|
}
|
|
451
665
|
}
|
|
452
|
-
|
|
453
666
|
// src/webapp-tool-factory.ts
|
|
667
|
+
import {
|
|
668
|
+
ProjectTypes as ProjectTypes3
|
|
669
|
+
} from "@uipath/solutionpackager-tool-core";
|
|
454
670
|
class WebAppToolFactory {
|
|
455
|
-
supportedTypes = [
|
|
671
|
+
supportedTypes = [ProjectTypes3.AppV2];
|
|
456
672
|
async createAsync(logger, fileSystem) {
|
|
457
673
|
return new WebAppTool(fileSystem, logger);
|
|
458
674
|
}
|
|
459
675
|
}
|
|
460
|
-
|
|
461
|
-
// src/index.ts
|
|
462
|
-
toolsFactoryRepository.registerProjectToolFactory(new WebAppToolFactory);
|
|
463
676
|
export {
|
|
677
|
+
WebAppVariantType,
|
|
464
678
|
WebAppToolFactory,
|
|
465
|
-
WebAppTool
|
|
679
|
+
WebAppTool,
|
|
680
|
+
WEBAPP_MANIFEST_FILE_NAME
|
|
466
681
|
};
|
|
682
|
+
|
|
683
|
+
//# debugId=D42E6DA7B2DF063064756E2164756E21
|
|
@@ -34,6 +34,7 @@ export type WebAppManifest<T extends WebAppVariantType = WebAppVariantType> = {
|
|
|
34
34
|
type: T;
|
|
35
35
|
solutionResourceSubType: string;
|
|
36
36
|
config?: ManifestConfigMap[T];
|
|
37
|
+
projectId?: string;
|
|
37
38
|
};
|
|
38
39
|
export declare const WEBAPP_MANIFEST_FILE_NAME = "webAppManifest.json";
|
|
39
40
|
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { IFileSystem } from "@uipath/solutionpackager-tool-core";
|
|
2
|
+
import type { WebAppManifest } from "../models/webapp-manifest.js";
|
|
3
|
+
import type { PackageArgs, VariantStrategy } from "./variant-strategy.js";
|
|
4
|
+
/**
|
|
5
|
+
* JS apps strategy for the JS variant.
|
|
6
|
+
* Packages a pre-built `.app` folder whose contents are placed under `content/app`
|
|
7
|
+
* in the resulting .nupkg.
|
|
8
|
+
*/
|
|
9
|
+
export declare class JsAppsStrategy implements VariantStrategy {
|
|
10
|
+
private readonly fileSystem;
|
|
11
|
+
constructor(fileSystem: IFileSystem);
|
|
12
|
+
/**
|
|
13
|
+
* Variant-specific validation: warn if the `.app` folder is missing or not a directory.
|
|
14
|
+
* Bundle path from the manifest is intentionally ignored for this variant.
|
|
15
|
+
*/
|
|
16
|
+
validateAsync(args: {
|
|
17
|
+
fileSystem: IFileSystem;
|
|
18
|
+
projectPath: string;
|
|
19
|
+
manifest: WebAppManifest;
|
|
20
|
+
logger?: {
|
|
21
|
+
info: (message: string) => void;
|
|
22
|
+
error: (message: string) => void;
|
|
23
|
+
progress: (message: string) => void;
|
|
24
|
+
warn?: (message: string) => void;
|
|
25
|
+
};
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
packageAsync(args: PackageArgs): Promise<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Prepare metadata files (operate.json, package-descriptor.json, bindings.json, bindings_v2.json, entry-points.json)
|
|
30
|
+
*/
|
|
31
|
+
private prepareMetadataFiles;
|
|
32
|
+
/**
|
|
33
|
+
* Create default entry-points.json structure
|
|
34
|
+
*/
|
|
35
|
+
private createDefaultEntryPoints;
|
|
36
|
+
/**
|
|
37
|
+
* Generate a cryptographically secure unique ID (UUID v4-like format)
|
|
38
|
+
*/
|
|
39
|
+
private generateUniqueId;
|
|
40
|
+
}
|
|
@@ -4,3 +4,8 @@ import type { WebAppManifest } from "../models/webapp-manifest.js";
|
|
|
4
4
|
* Load and parse webAppManifest.json from project path
|
|
5
5
|
*/
|
|
6
6
|
export declare function loadWebAppManifest(fileSystem: IFileSystem, projectPath: string): Promise<WebAppManifest | null>;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a stable projectId for a webapp, persisting it to
|
|
9
|
+
* webAppManifest.json so re-packs are stable.
|
|
10
|
+
*/
|
|
11
|
+
export declare function ensureWebAppProjectId(fileSystem: IFileSystem, projectPath: string): Promise<string>;
|
package/package.json
CHANGED
|
@@ -1,59 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"publish:dry": "bun publish --dry-run",
|
|
32
|
-
"publish:gh": "bun publish",
|
|
33
|
-
"version:patch": "bun version patch --no-git-tag-version",
|
|
34
|
-
"version:minor": "bun version minor --no-git-tag-version",
|
|
35
|
-
"version:major": "bun version major --no-git-tag-version",
|
|
36
|
-
"lint": "biome check ."
|
|
37
|
-
},
|
|
38
|
-
"files": [
|
|
39
|
-
"dist",
|
|
40
|
-
"!dist/**/*.map",
|
|
41
|
-
"src"
|
|
42
|
-
],
|
|
43
|
-
"author": "",
|
|
44
|
-
"license": "ISC",
|
|
45
|
-
"peerDependencies": {
|
|
46
|
-
"@uipath/solutionpackager-tool-core": "0.0.33"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@types/node": "^25.5.0",
|
|
50
|
-
"@uipath/solutionpackager-tool-core": "0.0.33",
|
|
51
|
-
"@vitest/browser": "^4.0.14",
|
|
52
|
-
"@vitest/browser-playwright": "^4.0.14",
|
|
53
|
-
"@vitest/coverage-v8": "^4.0.14",
|
|
54
|
-
"playwright": "^1.57.0",
|
|
55
|
-
"typescript": "^5.9.3",
|
|
56
|
-
"vitest": "^4.0.14"
|
|
57
|
-
},
|
|
58
|
-
"gitHead": "3f1b4d8e9f910be81e4cab956537f21dbd5d63ac"
|
|
2
|
+
"name": "@uipath/packager-tool-webapp",
|
|
3
|
+
"version": "1.197.0-preview.64",
|
|
4
|
+
"description": "UiPath WebApp tool implementation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"source": "./src/index.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/UiPath/cli.git",
|
|
15
|
+
"directory": "packages/packager/packager-tool-webapp"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"registry": "https://registry.npmjs.org/"
|
|
19
|
+
},
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"src"
|
|
24
|
+
],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "ISC",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@uipath/solutionpackager-tool-core": "1.197.0"
|
|
29
|
+
},
|
|
30
|
+
"gitHead": "3977b977945bf519336258da69fd271433eaaef4"
|
|
59
31
|
}
|
package/src/constants.ts
CHANGED
|
@@ -12,11 +12,26 @@ export const PROJECT_JSON_FILE = "project.json";
|
|
|
12
12
|
*/
|
|
13
13
|
export const DEFAULT_BUNDLE_PATH = "source/dist";
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Pre-built app folder for the JS variant (source)
|
|
17
|
+
*/
|
|
18
|
+
export const APP_FOLDER_NAME = ".app";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Destination folder inside the NuGet content folder for the JS variant
|
|
22
|
+
*/
|
|
23
|
+
export const CONTENT_APP_FOLDER_NAME = "app";
|
|
24
|
+
|
|
15
25
|
/**
|
|
16
26
|
* Target runtime for operate.json
|
|
17
27
|
*/
|
|
18
28
|
export const TARGET_RUNTIME = "Coded";
|
|
19
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Target runtime for operate.json
|
|
32
|
+
*/
|
|
33
|
+
export const TARGET_JS_RUNTIME = "JS";
|
|
34
|
+
|
|
20
35
|
/**
|
|
21
36
|
* Default entry point type
|
|
22
37
|
*/
|
|
@@ -41,6 +56,12 @@ export const ERROR_MESSAGES = {
|
|
|
41
56
|
BUNDLE_NOT_DIRECTORY: (path: string): string =>
|
|
42
57
|
`Bundle path ${path} exists but is not a directory.`,
|
|
43
58
|
|
|
59
|
+
APP_FOLDER_NOT_FOUND: (path: string): string =>
|
|
60
|
+
`.app folder not found at ${path}. Ensure the project contains a .app folder.`,
|
|
61
|
+
|
|
62
|
+
APP_FOLDER_NOT_DIRECTORY: (path: string): string =>
|
|
63
|
+
`.app path ${path} exists but is not a directory.`,
|
|
64
|
+
|
|
44
65
|
BUILD_NOT_SUPPORTED:
|
|
45
66
|
"Build execution (isCompiled=false) is not yet supported. Please build the project manually and set isCompiled=true.",
|
|
46
67
|
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// WebApp tool factory. Consumers register it explicitly via
|
|
2
|
+
// `toolsFactoryRepository.registerProjectToolFactory(new WebAppToolFactory())`.
|
|
3
|
+
export type { WebAppManifest } from "./models/webapp-manifest.js";
|
|
4
|
+
export {
|
|
5
|
+
WEBAPP_MANIFEST_FILE_NAME,
|
|
6
|
+
WebAppVariantType,
|
|
7
|
+
} from "./models/webapp-manifest.js";
|
|
4
8
|
export { WebAppTool } from "./webapp-tool.js";
|
|
5
9
|
export { WebAppToolFactory } from "./webapp-tool-factory.js";
|
|
6
|
-
|
|
7
|
-
toolsFactoryRepository.registerProjectToolFactory(new WebAppToolFactory());
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
type WebAppVariantType,
|
|
23
23
|
} from "../models/webapp-manifest.js";
|
|
24
24
|
import { copyDirectoryAsync } from "../utils/fs-helpers.js";
|
|
25
|
+
import { ensureWebAppProjectId } from "../utils/manifest-loader.js";
|
|
25
26
|
import type { PackageArgs, VariantStrategy } from "./variant-strategy.js";
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -179,7 +180,7 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
179
180
|
private async prepareMetadataFiles(
|
|
180
181
|
_localBuildFolder: string,
|
|
181
182
|
contentFolder: string,
|
|
182
|
-
|
|
183
|
+
_packageInfo: {
|
|
183
184
|
id: string;
|
|
184
185
|
version: string;
|
|
185
186
|
author?: string;
|
|
@@ -210,7 +211,10 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
210
211
|
NugetConstants.OperateFileName,
|
|
211
212
|
);
|
|
212
213
|
const operateModel: OperateFileModel & { targetRuntime: string } = {
|
|
213
|
-
projectId:
|
|
214
|
+
projectId: await ensureWebAppProjectId(
|
|
215
|
+
this.fileSystem,
|
|
216
|
+
projectPath,
|
|
217
|
+
),
|
|
214
218
|
main: mainFile,
|
|
215
219
|
contentType: ProjectTypes.WebApp,
|
|
216
220
|
targetFramework: TargetFramework.Portable,
|
|
@@ -235,8 +239,10 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
235
239
|
);
|
|
236
240
|
const manifestExists = await this.fileSystem.exists(manifestSourcePath);
|
|
237
241
|
if (manifestExists) {
|
|
238
|
-
const manifestContent =
|
|
239
|
-
|
|
242
|
+
const manifestContent = await this.fileSystem.readFile(
|
|
243
|
+
manifestSourcePath,
|
|
244
|
+
"utf-8",
|
|
245
|
+
);
|
|
240
246
|
if (manifestContent) {
|
|
241
247
|
await this.fileSystem.writeFile(
|
|
242
248
|
manifestDestPath,
|
|
@@ -251,8 +257,10 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
251
257
|
const uipathJsonExists =
|
|
252
258
|
await this.fileSystem.exists(uipathJsonSourcePath);
|
|
253
259
|
if (uipathJsonExists) {
|
|
254
|
-
const uipathJsonContent =
|
|
255
|
-
|
|
260
|
+
const uipathJsonContent = await this.fileSystem.readFile(
|
|
261
|
+
uipathJsonSourcePath,
|
|
262
|
+
"utf-8",
|
|
263
|
+
);
|
|
256
264
|
if (uipathJsonContent) {
|
|
257
265
|
await this.fileSystem.writeFile(
|
|
258
266
|
uipathJsonDestPath,
|
|
@@ -279,10 +287,32 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
279
287
|
|
|
280
288
|
// Create or copy bindings_v2.json (version 2.0)
|
|
281
289
|
const bindingsV2Path = Path.join(contentFolder, "bindings_v2.json");
|
|
282
|
-
const
|
|
290
|
+
const bindingsCandidatePaths = [
|
|
291
|
+
Path.join(projectPath, "source", "bindings.json"),
|
|
292
|
+
Path.join(projectPath, "bindings.json"),
|
|
293
|
+
Path.join(projectPath, "bindings_v2.json"),
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
let bindingsV2Json: string | null = null;
|
|
297
|
+
for (const candidate of bindingsCandidatePaths) {
|
|
298
|
+
if (await this.fileSystem.exists(candidate)) {
|
|
299
|
+
bindingsV2Json = await this.fileSystem.readFile(
|
|
300
|
+
candidate,
|
|
301
|
+
"utf-8",
|
|
302
|
+
);
|
|
303
|
+
if (bindingsV2Json) break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (!bindingsV2Json && (await this.fileSystem.exists(bindingsV2Path))) {
|
|
308
|
+
bindingsV2Json = await this.fileSystem.readFile(
|
|
309
|
+
bindingsV2Path,
|
|
310
|
+
"utf-8",
|
|
311
|
+
);
|
|
312
|
+
}
|
|
283
313
|
|
|
284
|
-
if (!
|
|
285
|
-
|
|
314
|
+
if (!bindingsV2Json) {
|
|
315
|
+
bindingsV2Json = JSON.stringify(
|
|
286
316
|
{
|
|
287
317
|
version: "2.0",
|
|
288
318
|
resources: [],
|
|
@@ -290,8 +320,8 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
290
320
|
null,
|
|
291
321
|
2,
|
|
292
322
|
);
|
|
293
|
-
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
294
323
|
}
|
|
324
|
+
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
295
325
|
|
|
296
326
|
// Create or copy entry-points.json
|
|
297
327
|
const entryPointsPath = Path.join(contentFolder, "entry-points.json");
|
|
@@ -308,9 +338,10 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
308
338
|
if (projectEntryPointsExists) {
|
|
309
339
|
const entryPointsData = await this.fileSystem.readFile(
|
|
310
340
|
projectEntryPointsPath,
|
|
341
|
+
"utf-8",
|
|
311
342
|
);
|
|
312
343
|
if (entryPointsData) {
|
|
313
|
-
entryPointsContent =
|
|
344
|
+
entryPointsContent = entryPointsData;
|
|
314
345
|
} else {
|
|
315
346
|
entryPointsContent = this.createDefaultEntryPoints(mainFile);
|
|
316
347
|
}
|
|
@@ -326,6 +357,8 @@ export class CodedAppStrategy implements VariantStrategy {
|
|
|
326
357
|
NugetConstants.PackageDescriptorFileName,
|
|
327
358
|
);
|
|
328
359
|
const packageDescriptor: PackageDescriptorFileModel = {
|
|
360
|
+
$schema:
|
|
361
|
+
"https://cloud.uipath.com/draft/2024-12/package-descriptor",
|
|
329
362
|
files: {
|
|
330
363
|
[NugetConstants.OperateFileName]: Path.join(
|
|
331
364
|
NugetConstants.ContentFolderName,
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IFileSystem,
|
|
3
|
+
OperateFileModel,
|
|
4
|
+
PackageDescriptorFileModel,
|
|
5
|
+
} from "@uipath/solutionpackager-tool-core";
|
|
6
|
+
import {
|
|
7
|
+
NugetConstants,
|
|
8
|
+
NugetPackager,
|
|
9
|
+
Path,
|
|
10
|
+
ProjectTypes,
|
|
11
|
+
TargetFramework,
|
|
12
|
+
} from "@uipath/solutionpackager-tool-core";
|
|
13
|
+
import {
|
|
14
|
+
APP_FOLDER_NAME,
|
|
15
|
+
CONTENT_APP_FOLDER_NAME,
|
|
16
|
+
DEFAULT_ENTRY_POINT_TYPE,
|
|
17
|
+
ERROR_MESSAGES,
|
|
18
|
+
TARGET_JS_RUNTIME,
|
|
19
|
+
} from "../constants.js";
|
|
20
|
+
import type { WebAppManifest } from "../models/webapp-manifest.js";
|
|
21
|
+
import { WEBAPP_MANIFEST_FILE_NAME } from "../models/webapp-manifest.js";
|
|
22
|
+
import { copyDirectoryAsync } from "../utils/fs-helpers.js";
|
|
23
|
+
import { ensureWebAppProjectId } from "../utils/manifest-loader.js";
|
|
24
|
+
import type { PackageArgs, VariantStrategy } from "./variant-strategy.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* JS apps strategy for the JS variant.
|
|
28
|
+
* Packages a pre-built `.app` folder whose contents are placed under `content/app`
|
|
29
|
+
* in the resulting .nupkg.
|
|
30
|
+
*/
|
|
31
|
+
export class JsAppsStrategy implements VariantStrategy {
|
|
32
|
+
constructor(private readonly fileSystem: IFileSystem) {}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Variant-specific validation: warn if the `.app` folder is missing or not a directory.
|
|
36
|
+
* Bundle path from the manifest is intentionally ignored for this variant.
|
|
37
|
+
*/
|
|
38
|
+
async validateAsync(args: {
|
|
39
|
+
fileSystem: IFileSystem;
|
|
40
|
+
projectPath: string;
|
|
41
|
+
manifest: WebAppManifest;
|
|
42
|
+
logger?: {
|
|
43
|
+
info: (message: string) => void;
|
|
44
|
+
error: (message: string) => void;
|
|
45
|
+
progress: (message: string) => void;
|
|
46
|
+
warn?: (message: string) => void;
|
|
47
|
+
};
|
|
48
|
+
}): Promise<void> {
|
|
49
|
+
const { projectPath, logger } = args;
|
|
50
|
+
const appFolder = Path.join(projectPath, APP_FOLDER_NAME);
|
|
51
|
+
|
|
52
|
+
const exists = await this.fileSystem.exists(appFolder);
|
|
53
|
+
if (!exists) {
|
|
54
|
+
const message = ERROR_MESSAGES.APP_FOLDER_NOT_FOUND(appFolder);
|
|
55
|
+
if (logger?.warn) {
|
|
56
|
+
logger.warn(message);
|
|
57
|
+
} else {
|
|
58
|
+
logger?.info(`Warning: ${message}`);
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const stat = await this.fileSystem.stat(appFolder);
|
|
64
|
+
if (!stat?.isDirectory()) {
|
|
65
|
+
const message = ERROR_MESSAGES.APP_FOLDER_NOT_DIRECTORY(appFolder);
|
|
66
|
+
if (logger?.warn) {
|
|
67
|
+
logger.warn(message);
|
|
68
|
+
} else {
|
|
69
|
+
logger?.info(`Warning: ${message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async packageAsync(args: PackageArgs): Promise<string> {
|
|
75
|
+
const { projectPath, manifest, outputPath, packageInfo, logger } = args;
|
|
76
|
+
|
|
77
|
+
logger?.info(
|
|
78
|
+
`Packaging JS variant: ${packageInfo.id}@${packageInfo.version}`,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const appFolder = Path.join(projectPath, APP_FOLDER_NAME);
|
|
82
|
+
|
|
83
|
+
logger?.progress("Validating .app folder...");
|
|
84
|
+
const appFolderExists = await this.fileSystem.exists(appFolder);
|
|
85
|
+
if (!appFolderExists) {
|
|
86
|
+
throw new Error(ERROR_MESSAGES.APP_FOLDER_NOT_FOUND(appFolder));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const appFolderStat = await this.fileSystem.stat(appFolder);
|
|
90
|
+
if (!appFolderStat?.isDirectory()) {
|
|
91
|
+
throw new Error(ERROR_MESSAGES.APP_FOLDER_NOT_DIRECTORY(appFolder));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Bundle directory structure: <output>/bundle/content/app
|
|
95
|
+
const localBuildFolder = Path.join(
|
|
96
|
+
outputPath,
|
|
97
|
+
NugetConstants.OutputFolderName,
|
|
98
|
+
);
|
|
99
|
+
const contentFolder = Path.join(
|
|
100
|
+
localBuildFolder,
|
|
101
|
+
NugetConstants.ContentFolderName,
|
|
102
|
+
);
|
|
103
|
+
const contentAppFolder = Path.join(
|
|
104
|
+
contentFolder,
|
|
105
|
+
CONTENT_APP_FOLDER_NAME,
|
|
106
|
+
);
|
|
107
|
+
await this.fileSystem.mkdir(contentFolder);
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
// Copy contents of .app into content/app
|
|
111
|
+
logger?.progress("Copying .app folder into content/app...");
|
|
112
|
+
await copyDirectoryAsync(
|
|
113
|
+
this.fileSystem,
|
|
114
|
+
appFolder,
|
|
115
|
+
contentAppFolder,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
logger?.progress("Preparing metadata files...");
|
|
119
|
+
await this.prepareMetadataFiles(
|
|
120
|
+
contentFolder,
|
|
121
|
+
contentAppFolder,
|
|
122
|
+
packageInfo,
|
|
123
|
+
manifest,
|
|
124
|
+
projectPath,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
logger?.progress("Creating NuGet package...");
|
|
128
|
+
const nupkgFileName = `${packageInfo.id}.${packageInfo.version}.nupkg`;
|
|
129
|
+
const nupkgPath = Path.join(outputPath, nupkgFileName);
|
|
130
|
+
|
|
131
|
+
const packager = new NugetPackager(this.fileSystem);
|
|
132
|
+
const result = await packager.packAsync(
|
|
133
|
+
localBuildFolder,
|
|
134
|
+
packageInfo,
|
|
135
|
+
nupkgPath,
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
logger?.info(`Package created successfully: ${result.outputPath}`);
|
|
139
|
+
return result.outputPath;
|
|
140
|
+
} finally {
|
|
141
|
+
try {
|
|
142
|
+
await this.fileSystem.rm(localBuildFolder);
|
|
143
|
+
} catch (cleanupError) {
|
|
144
|
+
logger?.error(
|
|
145
|
+
`Failed to cleanup build folder: ${
|
|
146
|
+
cleanupError instanceof Error
|
|
147
|
+
? cleanupError.message
|
|
148
|
+
: String(cleanupError)
|
|
149
|
+
}`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Prepare metadata files (operate.json, package-descriptor.json, bindings.json, bindings_v2.json, entry-points.json)
|
|
157
|
+
*/
|
|
158
|
+
private async prepareMetadataFiles(
|
|
159
|
+
contentFolder: string,
|
|
160
|
+
_contentAppFolder: string,
|
|
161
|
+
_packageInfo: {
|
|
162
|
+
id: string;
|
|
163
|
+
version: string;
|
|
164
|
+
author?: string;
|
|
165
|
+
description?: string;
|
|
166
|
+
},
|
|
167
|
+
_manifest: WebAppManifest,
|
|
168
|
+
projectPath: string,
|
|
169
|
+
): Promise<void> {
|
|
170
|
+
const mainFile = "index.html";
|
|
171
|
+
|
|
172
|
+
// Path referenced from within the package content folder
|
|
173
|
+
const mainRelativeToContent = `${CONTENT_APP_FOLDER_NAME}/${mainFile}`;
|
|
174
|
+
|
|
175
|
+
// operate.json in content folder
|
|
176
|
+
const operatePath = Path.join(
|
|
177
|
+
contentFolder,
|
|
178
|
+
NugetConstants.OperateFileName,
|
|
179
|
+
);
|
|
180
|
+
const operateModel: OperateFileModel & { targetRuntime: string } = {
|
|
181
|
+
projectId: await ensureWebAppProjectId(
|
|
182
|
+
this.fileSystem,
|
|
183
|
+
projectPath,
|
|
184
|
+
),
|
|
185
|
+
main: mainRelativeToContent,
|
|
186
|
+
contentType: ProjectTypes.WebApp,
|
|
187
|
+
targetFramework: TargetFramework.Portable,
|
|
188
|
+
targetRuntime: TARGET_JS_RUNTIME,
|
|
189
|
+
runtimeOptions: {
|
|
190
|
+
requiresUserInteraction: false,
|
|
191
|
+
isAttended: false,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const operateJson = JSON.stringify(operateModel, null, 2);
|
|
196
|
+
await this.fileSystem.writeFile(operatePath, operateJson);
|
|
197
|
+
|
|
198
|
+
// Copy webAppManifest.json from project root into content (as-is)
|
|
199
|
+
const manifestSourcePath = Path.join(
|
|
200
|
+
projectPath,
|
|
201
|
+
WEBAPP_MANIFEST_FILE_NAME,
|
|
202
|
+
);
|
|
203
|
+
const manifestDestPath = Path.join(
|
|
204
|
+
contentFolder,
|
|
205
|
+
WEBAPP_MANIFEST_FILE_NAME,
|
|
206
|
+
);
|
|
207
|
+
const manifestExists = await this.fileSystem.exists(manifestSourcePath);
|
|
208
|
+
if (manifestExists) {
|
|
209
|
+
const manifestContent =
|
|
210
|
+
await this.fileSystem.readFile(manifestSourcePath);
|
|
211
|
+
if (manifestContent) {
|
|
212
|
+
await this.fileSystem.writeFile(
|
|
213
|
+
manifestDestPath,
|
|
214
|
+
manifestContent,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Copy uipath.json from project root into content (if it exists)
|
|
220
|
+
const uipathJsonSourcePath = Path.join(projectPath, "uipath.json");
|
|
221
|
+
const uipathJsonDestPath = Path.join(contentFolder, "uipath.json");
|
|
222
|
+
const uipathJsonExists =
|
|
223
|
+
await this.fileSystem.exists(uipathJsonSourcePath);
|
|
224
|
+
if (uipathJsonExists) {
|
|
225
|
+
const uipathJsonContent =
|
|
226
|
+
await this.fileSystem.readFile(uipathJsonSourcePath);
|
|
227
|
+
if (uipathJsonContent) {
|
|
228
|
+
await this.fileSystem.writeFile(
|
|
229
|
+
uipathJsonDestPath,
|
|
230
|
+
uipathJsonContent,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Create or copy bindings.json (version 1.0)
|
|
236
|
+
const bindingsPath = Path.join(contentFolder, "bindings.json");
|
|
237
|
+
const bindingsExists = await this.fileSystem.exists(bindingsPath);
|
|
238
|
+
if (!bindingsExists) {
|
|
239
|
+
const bindingsJson = JSON.stringify(
|
|
240
|
+
{ version: "1.0", resources: [] },
|
|
241
|
+
null,
|
|
242
|
+
2,
|
|
243
|
+
);
|
|
244
|
+
await this.fileSystem.writeFile(bindingsPath, bindingsJson);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Create or copy bindings_v2.json (version 2.0)
|
|
248
|
+
const bindingsV2Path = Path.join(contentFolder, "bindings_v2.json");
|
|
249
|
+
const bindingsV2Exists = await this.fileSystem.exists(bindingsV2Path);
|
|
250
|
+
if (!bindingsV2Exists) {
|
|
251
|
+
const bindingsV2Json = JSON.stringify(
|
|
252
|
+
{ version: "2.0", resources: [] },
|
|
253
|
+
null,
|
|
254
|
+
2,
|
|
255
|
+
);
|
|
256
|
+
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Create or copy entry-points.json
|
|
260
|
+
const entryPointsPath = Path.join(contentFolder, "entry-points.json");
|
|
261
|
+
const projectEntryPointsPath = Path.join(
|
|
262
|
+
projectPath,
|
|
263
|
+
"entry-points.json",
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
let entryPointsContent: string;
|
|
267
|
+
const projectEntryPointsExists = await this.fileSystem.exists(
|
|
268
|
+
projectEntryPointsPath,
|
|
269
|
+
);
|
|
270
|
+
if (projectEntryPointsExists) {
|
|
271
|
+
const entryPointsData = await this.fileSystem.readFile(
|
|
272
|
+
projectEntryPointsPath,
|
|
273
|
+
);
|
|
274
|
+
if (entryPointsData) {
|
|
275
|
+
entryPointsContent = new TextDecoder().decode(entryPointsData);
|
|
276
|
+
} else {
|
|
277
|
+
entryPointsContent = this.createDefaultEntryPoints(
|
|
278
|
+
mainRelativeToContent,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
entryPointsContent = this.createDefaultEntryPoints(
|
|
283
|
+
mainRelativeToContent,
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
await this.fileSystem.writeFile(entryPointsPath, entryPointsContent);
|
|
288
|
+
|
|
289
|
+
// Create package-descriptor.json in content folder
|
|
290
|
+
const packageDescriptorPath = Path.join(
|
|
291
|
+
contentFolder,
|
|
292
|
+
NugetConstants.PackageDescriptorFileName,
|
|
293
|
+
);
|
|
294
|
+
const packageDescriptor: PackageDescriptorFileModel = {
|
|
295
|
+
files: {
|
|
296
|
+
[NugetConstants.OperateFileName]: Path.join(
|
|
297
|
+
NugetConstants.ContentFolderName,
|
|
298
|
+
NugetConstants.OperateFileName,
|
|
299
|
+
),
|
|
300
|
+
"entry-points.json": Path.join(
|
|
301
|
+
NugetConstants.ContentFolderName,
|
|
302
|
+
"entry-points.json",
|
|
303
|
+
),
|
|
304
|
+
"bindings.json": Path.join(
|
|
305
|
+
NugetConstants.ContentFolderName,
|
|
306
|
+
"bindings_v2.json",
|
|
307
|
+
),
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const packageDescriptorJson = JSON.stringify(
|
|
312
|
+
packageDescriptor,
|
|
313
|
+
null,
|
|
314
|
+
2,
|
|
315
|
+
);
|
|
316
|
+
await this.fileSystem.writeFile(
|
|
317
|
+
packageDescriptorPath,
|
|
318
|
+
packageDescriptorJson,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Create default entry-points.json structure
|
|
324
|
+
*/
|
|
325
|
+
private createDefaultEntryPoints(mainFilePath: string): string {
|
|
326
|
+
const uniqueId = this.generateUniqueId();
|
|
327
|
+
|
|
328
|
+
const entryPoints = {
|
|
329
|
+
$schema: "https://cloud.uipath.com/draft/2024-12/entry-point",
|
|
330
|
+
$id: "entry-points-doc-001",
|
|
331
|
+
entryPoints: [
|
|
332
|
+
{
|
|
333
|
+
filePath: mainFilePath,
|
|
334
|
+
uniqueId: uniqueId,
|
|
335
|
+
type: DEFAULT_ENTRY_POINT_TYPE,
|
|
336
|
+
input: {
|
|
337
|
+
amount: { type: "integer" },
|
|
338
|
+
id: { type: "string" },
|
|
339
|
+
},
|
|
340
|
+
output: {
|
|
341
|
+
status: { type: "string" },
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
return JSON.stringify(entryPoints, null, 2);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Generate a cryptographically secure unique ID (UUID v4-like format)
|
|
352
|
+
*/
|
|
353
|
+
private generateUniqueId(): string {
|
|
354
|
+
const randomBytes = new Uint8Array(16);
|
|
355
|
+
|
|
356
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
357
|
+
crypto.getRandomValues(randomBytes);
|
|
358
|
+
} else {
|
|
359
|
+
throw new Error("crypto.getRandomValues is not available");
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Set version (4) and variant bits according to UUID v4 spec
|
|
363
|
+
randomBytes[6] = (randomBytes[6] & 0x0f) | 0x40;
|
|
364
|
+
randomBytes[8] = (randomBytes[8] & 0x3f) | 0x80;
|
|
365
|
+
|
|
366
|
+
const hex = Array.from(randomBytes)
|
|
367
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
368
|
+
.join("");
|
|
369
|
+
|
|
370
|
+
return [
|
|
371
|
+
hex.substring(0, 8),
|
|
372
|
+
hex.substring(8, 12),
|
|
373
|
+
hex.substring(12, 16),
|
|
374
|
+
hex.substring(16, 20),
|
|
375
|
+
hex.substring(20, 32),
|
|
376
|
+
].join("-");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { IFileSystem } from "@uipath/solutionpackager-tool-core";
|
|
|
2
2
|
import type { WebAppManifest } from "../models/webapp-manifest.js";
|
|
3
3
|
import { WebAppVariantType } from "../models/webapp-manifest.js";
|
|
4
4
|
import { CodedAppStrategy } from "./coded-app-strategy.js";
|
|
5
|
+
import { JsAppsStrategy } from "./js-apps-strategy.js";
|
|
5
6
|
import type { VariantStrategy } from "./variant-strategy.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -26,9 +27,7 @@ export class VariantStrategyFactory {
|
|
|
26
27
|
return new CodedAppStrategy(fileSystem);
|
|
27
28
|
|
|
28
29
|
case WebAppVariantType.JS:
|
|
29
|
-
|
|
30
|
-
"JS variant is not yet implemented. Only Coded is supported in v1.",
|
|
31
|
-
);
|
|
30
|
+
return new JsAppsStrategy(fileSystem);
|
|
32
31
|
|
|
33
32
|
default:
|
|
34
33
|
throw new Error(
|
|
@@ -32,3 +32,32 @@ export async function loadWebAppManifest(
|
|
|
32
32
|
);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a stable projectId for a webapp, persisting it to
|
|
38
|
+
* webAppManifest.json so re-packs are stable.
|
|
39
|
+
*/
|
|
40
|
+
export async function ensureWebAppProjectId(
|
|
41
|
+
fileSystem: IFileSystem,
|
|
42
|
+
projectPath: string,
|
|
43
|
+
): Promise<string> {
|
|
44
|
+
const manifest = await loadWebAppManifest(fileSystem, projectPath);
|
|
45
|
+
if (
|
|
46
|
+
manifest &&
|
|
47
|
+
typeof manifest.projectId === "string" &&
|
|
48
|
+
manifest.projectId.length > 0
|
|
49
|
+
) {
|
|
50
|
+
return manifest.projectId;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const id = crypto.randomUUID();
|
|
54
|
+
if (manifest) {
|
|
55
|
+
const updated: WebAppManifest = { ...manifest, projectId: id };
|
|
56
|
+
const manifestPath = Path.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
57
|
+
await fileSystem.writeFile(
|
|
58
|
+
manifestPath,
|
|
59
|
+
`${JSON.stringify(updated, null, 2)}\n`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return id;
|
|
63
|
+
}
|