@uipath/solution-sdk 1.204.0-preview.249 → 1.204.0-preview.254

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.
@@ -5,7 +5,7 @@ compiled into its `dist/` output rather than installed alongside it.
5
5
  Their licences and copyright notices are reproduced here in full, as
6
6
  those licences require.
7
7
 
8
- 17 bundled dependencies:
8
+ 18 bundled dependencies:
9
9
 
10
10
  - @uipath/resource-builder-sdk@2025.11.0-alpha6004-4107 — ISC
11
11
  - bundle-name@4.1.0 — MIT
@@ -14,6 +14,7 @@ those licences require.
14
14
  - default-browser-id@5.0.1 — MIT
15
15
  - define-lazy-prop@3.0.0 — MIT
16
16
  - fflate@0.8.3 — MIT
17
+ - ignore@5.3.2 — MIT
17
18
  - is-docker@3.0.0 — MIT
18
19
  - is-in-ssh@1.0.0 — MIT
19
20
  - is-inside-container@1.0.0 — MIT
@@ -170,6 +171,36 @@ SOFTWARE.
170
171
 
171
172
  ---
172
173
 
174
+ ## ignore@5.3.2
175
+
176
+ SPDX: MIT
177
+
178
+ ```
179
+ Copyright (c) 2013 Kael Zhang <i@kael.me>, contributors
180
+ http://kael.me/
181
+
182
+ Permission is hereby granted, free of charge, to any person obtaining
183
+ a copy of this software and associated documentation files (the
184
+ "Software"), to deal in the Software without restriction, including
185
+ without limitation the rights to use, copy, modify, merge, publish,
186
+ distribute, sublicense, and/or sell copies of the Software, and to
187
+ permit persons to whom the Software is furnished to do so, subject to
188
+ the following conditions:
189
+
190
+ The above copyright notice and this permission notice shall be
191
+ included in all copies or substantial portions of the Software.
192
+
193
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
194
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
195
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
196
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
197
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
198
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
199
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
200
+ ```
201
+
202
+ ---
203
+
173
204
  ## is-docker@3.0.0
174
205
 
175
206
  SPDX: MIT
package/dist/index.js CHANGED
@@ -24,7 +24,270 @@ import {
24
24
  zipSync
25
25
  } from "./index-fb21bjwj.js";
26
26
  import"./index-g0hcxnae.js";
27
- import"./index-1de529jm.js";
27
+ import {
28
+ __commonJS,
29
+ __toESM
30
+ } from "./index-1de529jm.js";
31
+
32
+ // ../../node_modules/ignore/index.js
33
+ var require_ignore = __commonJS(function(exports, module) {
34
+ function makeArray(subject) {
35
+ return Array.isArray(subject) ? subject : [subject];
36
+ }
37
+ var EMPTY = "";
38
+ var SPACE = " ";
39
+ var ESCAPE = "\\";
40
+ var REGEX_TEST_BLANK_LINE = /^\s+$/;
41
+ var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
42
+ var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
43
+ var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
44
+ var REGEX_SPLITALL_CRLF = /\r?\n/g;
45
+ var REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/;
46
+ var SLASH = "/";
47
+ var TMP_KEY_IGNORE = "node-ignore";
48
+ if (typeof Symbol !== "undefined") {
49
+ TMP_KEY_IGNORE = Symbol.for("node-ignore");
50
+ }
51
+ var KEY_IGNORE = TMP_KEY_IGNORE;
52
+ var define = (object, key, value) => Object.defineProperty(object, key, { value });
53
+ var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
54
+ var RETURN_FALSE = () => false;
55
+ var sanitizeRange = (range) => range.replace(REGEX_REGEXP_RANGE, (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match : EMPTY);
56
+ var cleanRangeBackSlash = (slashes) => {
57
+ const { length } = slashes;
58
+ return slashes.slice(0, length - length % 2);
59
+ };
60
+ var REPLACERS = [
61
+ [
62
+ /^\uFEFF/,
63
+ () => EMPTY
64
+ ],
65
+ [
66
+ /((?:\\\\)*?)(\\?\s+)$/,
67
+ (_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
68
+ ],
69
+ [
70
+ /(\\+?)\s/g,
71
+ (_, m1) => {
72
+ const { length } = m1;
73
+ return m1.slice(0, length - length % 2) + SPACE;
74
+ }
75
+ ],
76
+ [
77
+ /[\\$.|*+(){^]/g,
78
+ (match) => `\\${match}`
79
+ ],
80
+ [
81
+ /(?!\\)\?/g,
82
+ () => "[^/]"
83
+ ],
84
+ [
85
+ /^\//,
86
+ () => "^"
87
+ ],
88
+ [
89
+ /\//g,
90
+ () => "\\/"
91
+ ],
92
+ [
93
+ /^\^*\\\*\\\*\\\//,
94
+ () => "^(?:.*\\/)?"
95
+ ],
96
+ [
97
+ /^(?=[^^])/,
98
+ function startingReplacer() {
99
+ return !/\/(?!$)/.test(this) ? "(?:^|\\/)" : "^";
100
+ }
101
+ ],
102
+ [
103
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
104
+ (_, index, str) => index + 6 < str.length ? "(?:\\/[^\\/]+)*" : "\\/.+"
105
+ ],
106
+ [
107
+ /(^|[^\\]+)(\\\*)+(?=.+)/g,
108
+ (_, p1, p2) => {
109
+ const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
110
+ return p1 + unescaped;
111
+ }
112
+ ],
113
+ [
114
+ /\\\\\\(?=[$.|*+(){^])/g,
115
+ () => ESCAPE
116
+ ],
117
+ [
118
+ /\\\\/g,
119
+ () => ESCAPE
120
+ ],
121
+ [
122
+ /(\\)?\[([^\]/]*?)(\\*)($|\])/g,
123
+ (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` : close === "]" ? endEscape.length % 2 === 0 ? `[${sanitizeRange(range)}${endEscape}]` : "[]" : "[]"
124
+ ],
125
+ [
126
+ /(?:[^*])$/,
127
+ (match) => /\/$/.test(match) ? `${match}$` : `${match}(?=$|\\/$)`
128
+ ],
129
+ [
130
+ /(\^|\\\/)?\\\*$/,
131
+ (_, p1) => {
132
+ const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
133
+ return `${prefix}(?=$|\\/$)`;
134
+ }
135
+ ]
136
+ ];
137
+ var regexCache = Object.create(null);
138
+ var makeRegex = (pattern, ignoreCase) => {
139
+ let source = regexCache[pattern];
140
+ if (!source) {
141
+ source = REPLACERS.reduce((prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)), pattern);
142
+ regexCache[pattern] = source;
143
+ }
144
+ return ignoreCase ? new RegExp(source, "i") : new RegExp(source);
145
+ };
146
+ var isString = (subject) => typeof subject === "string";
147
+ var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
148
+ var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF);
149
+
150
+ class IgnoreRule {
151
+ constructor(origin, pattern, negative, regex) {
152
+ this.origin = origin;
153
+ this.pattern = pattern;
154
+ this.negative = negative;
155
+ this.regex = regex;
156
+ }
157
+ }
158
+ var createRule = (pattern, ignoreCase) => {
159
+ const origin = pattern;
160
+ let negative = false;
161
+ if (pattern.indexOf("!") === 0) {
162
+ negative = true;
163
+ pattern = pattern.substr(1);
164
+ }
165
+ pattern = pattern.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
166
+ const regex = makeRegex(pattern, ignoreCase);
167
+ return new IgnoreRule(origin, pattern, negative, regex);
168
+ };
169
+ var throwError = (message, Ctor) => {
170
+ throw new Ctor(message);
171
+ };
172
+ var checkPath = (path, originalPath, doThrow) => {
173
+ if (!isString(path)) {
174
+ return doThrow(`path must be a string, but got \`${originalPath}\``, TypeError);
175
+ }
176
+ if (!path) {
177
+ return doThrow(`path must not be empty`, TypeError);
178
+ }
179
+ if (checkPath.isNotRelative(path)) {
180
+ const r = "`path.relative()`d";
181
+ return doThrow(`path should be a ${r} string, but got "${originalPath}"`, RangeError);
182
+ }
183
+ return true;
184
+ };
185
+ var isNotRelative = (path) => REGEX_TEST_INVALID_PATH.test(path);
186
+ checkPath.isNotRelative = isNotRelative;
187
+ checkPath.convert = (p) => p;
188
+
189
+ class Ignore {
190
+ constructor({
191
+ ignorecase = true,
192
+ ignoreCase = ignorecase,
193
+ allowRelativePaths = false
194
+ } = {}) {
195
+ define(this, KEY_IGNORE, true);
196
+ this._rules = [];
197
+ this._ignoreCase = ignoreCase;
198
+ this._allowRelativePaths = allowRelativePaths;
199
+ this._initCache();
200
+ }
201
+ _initCache() {
202
+ this._ignoreCache = Object.create(null);
203
+ this._testCache = Object.create(null);
204
+ }
205
+ _addPattern(pattern) {
206
+ if (pattern && pattern[KEY_IGNORE]) {
207
+ this._rules = this._rules.concat(pattern._rules);
208
+ this._added = true;
209
+ return;
210
+ }
211
+ if (checkPattern(pattern)) {
212
+ const rule = createRule(pattern, this._ignoreCase);
213
+ this._added = true;
214
+ this._rules.push(rule);
215
+ }
216
+ }
217
+ add(pattern) {
218
+ this._added = false;
219
+ makeArray(isString(pattern) ? splitPattern(pattern) : pattern).forEach(this._addPattern, this);
220
+ if (this._added) {
221
+ this._initCache();
222
+ }
223
+ return this;
224
+ }
225
+ addPattern(pattern) {
226
+ return this.add(pattern);
227
+ }
228
+ _testOne(path, checkUnignored) {
229
+ let ignored = false;
230
+ let unignored = false;
231
+ this._rules.forEach((rule) => {
232
+ const { negative } = rule;
233
+ if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
234
+ return;
235
+ }
236
+ const matched = rule.regex.test(path);
237
+ if (matched) {
238
+ ignored = !negative;
239
+ unignored = negative;
240
+ }
241
+ });
242
+ return {
243
+ ignored,
244
+ unignored
245
+ };
246
+ }
247
+ _test(originalPath, cache, checkUnignored, slices) {
248
+ const path = originalPath && checkPath.convert(originalPath);
249
+ checkPath(path, originalPath, this._allowRelativePaths ? RETURN_FALSE : throwError);
250
+ return this._t(path, cache, checkUnignored, slices);
251
+ }
252
+ _t(path, cache, checkUnignored, slices) {
253
+ if (path in cache) {
254
+ return cache[path];
255
+ }
256
+ if (!slices) {
257
+ slices = path.split(SLASH);
258
+ }
259
+ slices.pop();
260
+ if (!slices.length) {
261
+ return cache[path] = this._testOne(path, checkUnignored);
262
+ }
263
+ const parent = this._t(slices.join(SLASH) + SLASH, cache, checkUnignored, slices);
264
+ return cache[path] = parent.ignored ? parent : this._testOne(path, checkUnignored);
265
+ }
266
+ ignores(path) {
267
+ return this._test(path, this._ignoreCache, false).ignored;
268
+ }
269
+ createFilter() {
270
+ return (path) => !this.ignores(path);
271
+ }
272
+ filter(paths) {
273
+ return makeArray(paths).filter(this.createFilter());
274
+ }
275
+ test(path) {
276
+ return this._test(path, this._testCache, true);
277
+ }
278
+ }
279
+ var factory = (options) => new Ignore(options);
280
+ var isPathValid = (path) => checkPath(path && checkPath.convert(path), path, RETURN_FALSE);
281
+ factory.isPathValid = isPathValid;
282
+ factory.default = factory;
283
+ module.exports = factory;
284
+ if (typeof process !== "undefined" && (process.env && process.env.IGNORE_TEST_WIN32 || process.platform === "win32")) {
285
+ const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
286
+ checkPath.convert = makePosix;
287
+ const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
288
+ checkPath.isNotRelative = (path) => REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) || isNotRelative(path);
289
+ }
290
+ });
28
291
 
29
292
  // generated/src/runtime.ts
30
293
  var BASE_PATH = "https://alpha.uipath.com/uipattycyrhx/abizon_1/automationsolutions_".replace(/\/+$/, "");
@@ -326,7 +589,7 @@ var package_default = {
326
589
  name: "@uipath/solution-sdk",
327
590
  author: "UiPath",
328
591
  license: "SEE LICENSE IN LICENSE.txt",
329
- version: "1.204.0-preview.249",
592
+ version: "1.204.0-preview.254",
330
593
  repository: {
331
594
  type: "git",
332
595
  url: "https://github.com/UiPath/cli.git",
@@ -382,6 +645,7 @@ var package_default = {
382
645
  "@uipath/studioweb-sdk": "workspace:*",
383
646
  "@types/node": "^25.5.2",
384
647
  fflate: "^0.8.2",
648
+ ignore: "^5.3.2",
385
649
  typescript: "^7.0.2"
386
650
  }
387
651
  };
@@ -4337,6 +4601,7 @@ function assertStudioWebCompatibleProjects(projects) {
4337
4601
  }
4338
4602
 
4339
4603
  // src/zip-utils.ts
4604
+ var import_ignore = __toESM(require_ignore(), 1);
4340
4605
  var DEFAULT_EXCLUDED_DIR_NAMES = new Set([
4341
4606
  ".venv",
4342
4607
  "node_modules",
@@ -4358,18 +4623,31 @@ function isDefaultExcludedFileName(name) {
4358
4623
  }
4359
4624
  var UIPIGNORE_FILENAME = ".uipignore";
4360
4625
  function parseUipignore(body) {
4361
- const names = new Set;
4362
- for (const rawLine of body.split(/\r?\n/)) {
4363
- const line = rawLine.split("#")[0]?.trim();
4364
- if (!line) {
4626
+ return body.split(/\r?\n/).filter((line) => line.trim() !== "" && !line.startsWith("#"));
4627
+ }
4628
+ function createUipignoreRules(baseDir, patterns) {
4629
+ const matcher = import_ignore.default().add([...patterns]);
4630
+ return {
4631
+ baseDir,
4632
+ patterns,
4633
+ ignores: (relativePath) => matcher.ignores(relativePath)
4634
+ };
4635
+ }
4636
+ var UNMATCHABLE_RELATIVE_PATH = /^\.+$|^\.*\//;
4637
+ function isIgnoredByRules(fs, rules, fullPath, isDirectory) {
4638
+ if (!rules) {
4639
+ return false;
4640
+ }
4641
+ for (const rule of rules) {
4642
+ const rel = fs.path.relative(rule.baseDir, fullPath).replace(/\\/g, "/");
4643
+ if (!rel || UNMATCHABLE_RELATIVE_PATH.test(rel) || fs.path.isAbsolute(rel)) {
4365
4644
  continue;
4366
4645
  }
4367
- if (line.includes("/") || line.includes("\\")) {
4368
- continue;
4646
+ if (rule.ignores(isDirectory ? `${rel}/` : rel)) {
4647
+ return true;
4369
4648
  }
4370
- names.add(line);
4371
4649
  }
4372
- return names;
4650
+ return false;
4373
4651
  }
4374
4652
  async function collectTree(fs, dir, options = {}) {
4375
4653
  const files = [];
@@ -4392,12 +4670,12 @@ async function collectTree(fs, dir, options = {}) {
4392
4670
  const fullPath = fs.path.join(current, entryName);
4393
4671
  const entryStat = await fs.stat(fullPath);
4394
4672
  if (entryStat?.isDirectory()) {
4395
- if (excluded.has(entryName)) {
4673
+ if (excluded.has(entryName) || isIgnoredByRules(fs, options.ignoreRules, fullPath, true)) {
4396
4674
  continue;
4397
4675
  }
4398
4676
  await walk(fullPath, false);
4399
4677
  } else if (entryStat?.isFile()) {
4400
- if (isDefaultExcludedFileName(entryName)) {
4678
+ if (isDefaultExcludedFileName(entryName) || isIgnoredByRules(fs, options.ignoreRules, fullPath, false)) {
4401
4679
  continue;
4402
4680
  }
4403
4681
  files.push(fullPath);
@@ -4500,38 +4778,43 @@ function countCentralDirectoryEntries(view, cdOffset, cdSize) {
4500
4778
  }
4501
4779
 
4502
4780
  // src/bundle-service.ts
4781
+ class UipignoreExcludesProjectError extends Error {
4782
+ projectManifestPath;
4783
+ constructor(projectManifestPath) {
4784
+ super(`${UIPIGNORE_FILENAME} excludes ${projectManifestPath}, which the solution references. A project listed in the .uipx cannot be left out of the bundle.`);
4785
+ this.projectManifestPath = projectManifestPath;
4786
+ this.name = "UipignoreExcludesProjectError";
4787
+ }
4788
+ }
4503
4789
  async function readUipignore(fs, dir) {
4504
4790
  const ignorePath = fs.path.join(dir, UIPIGNORE_FILENAME);
4505
4791
  if (!await fs.exists(ignorePath)) {
4506
- return new Set;
4792
+ return;
4507
4793
  }
4508
4794
  try {
4509
4795
  const body = await fs.readFile(ignorePath, "utf-8");
4510
- if (!body) {
4511
- return new Set;
4796
+ const patterns = body ? parseUipignore(body) : [];
4797
+ if (patterns.length === 0) {
4798
+ return;
4512
4799
  }
4513
- return parseUipignore(body);
4800
+ return createUipignoreRules(dir, patterns);
4514
4801
  } catch (err) {
4515
4802
  logger.warn(`Could not read ${UIPIGNORE_FILENAME}; ignoring it: ${String(err)}`);
4516
- return new Set;
4803
+ return;
4517
4804
  }
4518
4805
  }
4519
- async function mergeProjectUipignore(fs, projectPath, projectLabel, solutionExcludeDirs) {
4520
- const projectExtra = await readUipignore(fs, projectPath);
4521
- if (projectExtra.size === 0) {
4522
- return solutionExcludeDirs;
4806
+ async function mergeProjectUipignore(fs, projectPath, projectLabel, solutionRules) {
4807
+ const projectRules = await readUipignore(fs, projectPath);
4808
+ if (!projectRules) {
4809
+ return solutionRules;
4523
4810
  }
4524
- const merged = new Set(solutionExcludeDirs);
4525
- for (const name of projectExtra) {
4526
- merged.add(name);
4527
- }
4528
- logger.info(`[${projectLabel}] Applying ${projectExtra.size} extra exclude(s) from project ${UIPIGNORE_FILENAME}: ${[...projectExtra].join(", ")}`);
4529
- return merged;
4811
+ logger.info(`[${projectLabel}] Applying ${projectRules.patterns.length} extra exclude(s) from project ${UIPIGNORE_FILENAME}: ${projectRules.patterns.join(", ")}`);
4812
+ return [...solutionRules, projectRules];
4530
4813
  }
4531
4814
  var toForwardSlash = (p) => p.replace(/\\/g, "/");
4532
- async function mirrorTree(fs, srcDir, relativeBase, destBaseDir, additionalExcludeDirs) {
4815
+ async function mirrorTree(fs, srcDir, relativeBase, destBaseDir, ignoreRules) {
4533
4816
  const { files, emptyDirs } = await collectTree(fs, srcDir, {
4534
- additionalExcludeDirs
4817
+ ignoreRules
4535
4818
  });
4536
4819
  if (files.length === 0 && emptyDirs.length === 0) {
4537
4820
  const rootRel = fs.path.relative(relativeBase, srcDir);
@@ -4558,14 +4841,8 @@ async function mirrorTree(fs, srcDir, relativeBase, destBaseDir, additionalExclu
4558
4841
  await fs.mkdir(fs.path.join(destBaseDir, relPath));
4559
4842
  }
4560
4843
  }
4561
- async function flattenProjectDir(fs, srcProjectDir, destProjectDir, additionalExcludeDirs) {
4844
+ async function flattenProjectDir(fs, srcProjectDir, destProjectDir, ignoreRules) {
4562
4845
  await fs.mkdir(destProjectDir);
4563
- const topLevelExclude = new Set(DEFAULT_EXCLUDED_DIR_NAMES);
4564
- if (additionalExcludeDirs) {
4565
- for (const name of additionalExcludeDirs) {
4566
- topLevelExclude.add(name);
4567
- }
4568
- }
4569
4846
  const entries = await fs.readdir(srcProjectDir);
4570
4847
  for (const entryName of entries) {
4571
4848
  const srcPath = fs.path.join(srcProjectDir, entryName);
@@ -4574,7 +4851,7 @@ async function flattenProjectDir(fs, srcProjectDir, destProjectDir, additionalEx
4574
4851
  continue;
4575
4852
  }
4576
4853
  if (entryStat.isFile()) {
4577
- if (isDefaultExcludedFileName(entryName)) {
4854
+ if (isDefaultExcludedFileName(entryName) || isIgnoredByRules(fs, ignoreRules, srcPath, false)) {
4578
4855
  continue;
4579
4856
  }
4580
4857
  const data = await fs.readFile(srcPath);
@@ -4582,13 +4859,13 @@ async function flattenProjectDir(fs, srcProjectDir, destProjectDir, additionalEx
4582
4859
  await fs.writeFile(fs.path.join(destProjectDir, entryName), data);
4583
4860
  }
4584
4861
  } else if (entryStat.isDirectory()) {
4585
- if (topLevelExclude.has(entryName)) {
4862
+ if (DEFAULT_EXCLUDED_DIR_NAMES.has(entryName) || isIgnoredByRules(fs, ignoreRules, srcPath, true)) {
4586
4863
  continue;
4587
4864
  }
4588
4865
  if (entryName === "content" || entryName === "flow_files") {
4589
- await mirrorTree(fs, srcPath, srcPath, destProjectDir, additionalExcludeDirs);
4866
+ await mirrorTree(fs, srcPath, srcPath, destProjectDir, ignoreRules);
4590
4867
  } else {
4591
- await mirrorTree(fs, srcPath, srcProjectDir, destProjectDir, additionalExcludeDirs);
4868
+ await mirrorTree(fs, srcPath, srcProjectDir, destProjectDir, ignoreRules);
4592
4869
  }
4593
4870
  }
4594
4871
  }
@@ -4603,14 +4880,12 @@ async function bundleSolution(fs, solutionDir, outputDir, outputName) {
4603
4880
  throw new Error(`Not a directory: ${resolvedPath}. Provide the solution directory containing a .uipx file.`);
4604
4881
  }
4605
4882
  const { uipx, uipxFileName } = await readUipxFile(fs, resolvedPath);
4606
- const additionalExcludeDirs = await readUipignore(fs, resolvedPath);
4607
- if (additionalExcludeDirs.size > 0) {
4608
- logger.info(`Applying ${additionalExcludeDirs.size} extra exclude(s) from .uipignore: ${[...additionalExcludeDirs].join(", ")}`);
4609
- }
4610
- const effectiveExclude = new Set(DEFAULT_EXCLUDED_DIR_NAMES);
4611
- for (const name of additionalExcludeDirs) {
4612
- effectiveExclude.add(name);
4883
+ const solutionUipignore = await readUipignore(fs, resolvedPath);
4884
+ const solutionRules = solutionUipignore ? [solutionUipignore] : [];
4885
+ if (solutionUipignore) {
4886
+ logger.info(`Applying ${solutionUipignore.patterns.length} extra exclude(s) from ${UIPIGNORE_FILENAME}: ${solutionUipignore.patterns.join(", ")}`);
4613
4887
  }
4888
+ const isTopLevelTreeExcluded = (treePath, name) => DEFAULT_EXCLUDED_DIR_NAMES.has(name) || isIgnoredByRules(fs, solutionRules, treePath, true);
4614
4889
  for (const project of uipx.Projects) {
4615
4890
  project.ProjectRelativePath = toForwardSlash(project.ProjectRelativePath);
4616
4891
  }
@@ -4635,16 +4910,20 @@ async function bundleSolution(fs, solutionDir, outputDir, outputName) {
4635
4910
  if (!projectStat) {
4636
4911
  throw new Error(`Project directory not found: ${srcProjectPath}`);
4637
4912
  }
4638
- const projectExcludeDirs = await mergeProjectUipignore(fs, srcProjectPath, projectDir, additionalExcludeDirs);
4639
- await flattenProjectDir(fs, srcProjectPath, fs.path.join(stagingDir, projectDir), projectExcludeDirs);
4913
+ const projectRules = await mergeProjectUipignore(fs, srcProjectPath, projectDir, solutionRules);
4914
+ const manifestPath = fs.path.join(resolvedPath, project.ProjectRelativePath);
4915
+ if (isIgnoredByRules(fs, projectRules, manifestPath, false)) {
4916
+ throw new UipignoreExcludesProjectError(project.ProjectRelativePath);
4917
+ }
4918
+ await flattenProjectDir(fs, srcProjectPath, fs.path.join(stagingDir, projectDir), projectRules);
4640
4919
  }
4641
4920
  const resourcesPath = fs.path.join(resolvedPath, "resources");
4642
- if (!effectiveExclude.has("resources") && await fs.exists(resourcesPath)) {
4643
- await mirrorTree(fs, resourcesPath, resolvedPath, stagingDir, additionalExcludeDirs);
4921
+ if (!isTopLevelTreeExcluded(resourcesPath, "resources") && await fs.exists(resourcesPath)) {
4922
+ await mirrorTree(fs, resourcesPath, resolvedPath, stagingDir, solutionRules);
4644
4923
  }
4645
4924
  const userProfilePath = fs.path.join(resolvedPath, "userProfile");
4646
- if (!effectiveExclude.has("userProfile") && await fs.exists(userProfilePath)) {
4647
- await mirrorTree(fs, userProfilePath, resolvedPath, stagingDir, additionalExcludeDirs);
4925
+ if (!isTopLevelTreeExcluded(userProfilePath, "userProfile") && await fs.exists(userProfilePath)) {
4926
+ await mirrorTree(fs, userProfilePath, resolvedPath, stagingDir, solutionRules);
4648
4927
  }
4649
4928
  const resolvedOutputDir = fs.path.resolve(outputDir);
4650
4929
  if (!await fs.exists(resolvedOutputDir)) {
@@ -5316,6 +5595,7 @@ export {
5316
5595
  SolutionUploadHttpError,
5317
5596
  StudioWebIncompatibleProjectError,
5318
5597
  TextApiResponse,
5598
+ UipignoreExcludesProjectError,
5319
5599
  VoidApiResponse,
5320
5600
  WorkflowAction,
5321
5601
  WorkflowActionFromJSON,
@@ -5411,4 +5691,4 @@ export {
5411
5691
  uploadOrOverwriteSolution
5412
5692
  };
5413
5693
 
5414
- //# debugId=14F18399CD557CE064756E2164756E21
5694
+ //# debugId=E7BE3615C046406164756E2164756E21
@@ -5,6 +5,15 @@
5
5
  */
6
6
  import type { IFileSystem } from "@uipath/filesystem";
7
7
  import type { BundleResult } from "./types";
8
+ /**
9
+ * Thrown when a `.uipignore` pattern would drop a project the `.uipx` lists.
10
+ * `SolutionStorage.json` would still name that project, so the archive would
11
+ * be broken on import; refusing up front is the only honest outcome.
12
+ */
13
+ export declare class UipignoreExcludesProjectError extends Error {
14
+ readonly projectManifestPath: string;
15
+ constructor(projectManifestPath: string);
16
+ }
8
17
  /**
9
18
  * Bundle a solution directory into a .uis file.
10
19
  * Validates the .uipx file, flattens project directories, and zips everything.
@@ -1,7 +1,7 @@
1
1
  import "./user-agent.js";
2
2
  export { getAvailablePublishLocationsV2, type PublishLocationType, type PublishLocationV2, } from "@uipath/studioweb-sdk";
3
3
  export * from "../generated/src/index.js";
4
- export { buildSolutionPackageFromDir, bundleSolution, resolveSolutionDir, } from "./bundle-service";
4
+ export { buildSolutionPackageFromDir, bundleSolution, resolveSolutionDir, UipignoreExcludesProjectError, } from "./bundle-service";
5
5
  export { getProjectDebugStatus, isDebugProvisioningSucceeded, isDebugProvisioningTerminal, type ProjectDebugStatusClientConfig, type ProjectDebugStatusError, type ProjectDebugStatusResponse, } from "./project-debug-status";
6
6
  export { type PackageVersionSearchFilter, type PackageVersionSearchRow, type PackageVersionsClientConfig, searchPackageVersions, } from "./search-package-versions";
7
7
  export type { AutoCreatedSolution, ParentSolutionDiscovery, PrepareProjectLocationOptions, PrepareProjectLocationResult, ProjectSolutionRegistration, RegisterProjectOptions, SolutionManifestCreation, } from "./solution-file";
@@ -26,8 +26,9 @@ import type { IFileSystem } from "@uipath/filesystem";
26
26
  * `.project` (IDE state) and `.agent-builder` (inline agents)
27
27
  * must still ship.
28
28
  *
29
- * Callers can extend this set per-walk via the `additionalExcludeDirs` option
30
- * (sourced from a `.uipignore` file at the solution root by bundle-service).
29
+ * Callers can extend this set per-walk via the `additionalExcludeDirs` option.
30
+ * User-authored excludes come from `.uipignore` files and go through
31
+ * `ignoreRules` instead (see {@link UipignoreRules}).
31
32
  */
32
33
  export declare const DEFAULT_EXCLUDED_DIR_NAMES: ReadonlySet<string>;
33
34
  /**
@@ -46,13 +47,38 @@ export declare function isDefaultExcludedFileName(name: string): boolean;
46
47
  /** File name read by bundle-service to extend the default exclude set. */
47
48
  export declare const UIPIGNORE_FILENAME = ".uipignore";
48
49
  /**
49
- * Parse a `.uipignore` file body: one directory name per line, `#` for line
50
- * comments, blank lines ignored. Returns the names as a Set. The parser is
51
- * deliberately minimal — no globs, no negation, no path separators. Each
52
- * entry matches by exact directory name at any depth (same semantics as the
53
- * built-in defaults).
50
+ * Split a `.uipignore` file body into its patterns: one per line, skipping
51
+ * blank lines and lines that start with `#`. Nothing else is interpreted here.
52
+ * The patterns go to the `ignore` package as-is, so the syntax is plain
53
+ * gitignore: globs (`*.log`), anchored paths (`/dist`, `src/generated/`), a
54
+ * trailing `/` for directories only, `!` to re-include. `codedapp push` feeds
55
+ * the same file to `ignore` raw, so the two commands read it identically.
54
56
  */
55
- export declare function parseUipignore(body: string): Set<string>;
57
+ export declare function parseUipignore(body: string): string[];
58
+ /**
59
+ * Parsed `.uipignore` patterns, matched against paths relative to `baseDir`
60
+ * (the directory that holds the file). `ignores` takes a forward-slash path
61
+ * relative to `baseDir`, with a trailing `/` for a directory.
62
+ */
63
+ export interface UipignoreRules {
64
+ baseDir: string;
65
+ patterns: readonly string[];
66
+ ignores: (relativePath: string) => boolean;
67
+ }
68
+ /** Build matchable rules from `.uipignore` patterns rooted at `baseDir`. */
69
+ export declare function createUipignoreRules(baseDir: string, patterns: readonly string[]): UipignoreRules;
70
+ /**
71
+ * True when any of `rules` ignores `fullPath`. Each rule set only sees paths
72
+ * under its own `baseDir`; paths outside it are never matched.
73
+ */
74
+ export declare function isIgnoredByRules(fs: IFileSystem, rules: readonly UipignoreRules[] | undefined, fullPath: string, isDirectory: boolean): boolean;
75
+ /** What {@link collectTree} skips on top of the built-in defaults. */
76
+ export interface CollectTreeOptions {
77
+ /** Extra directory names to skip at any depth (caller-supplied). */
78
+ additionalExcludeDirs?: Iterable<string>;
79
+ /** Parsed `.uipignore` rules (gitignore syntax). */
80
+ ignoreRules?: readonly UipignoreRules[];
81
+ }
56
82
  /**
57
83
  * Recursively walk `dir`, returning every file path and every empty directory
58
84
  * path beneath it. An empty directory is a directory whose `readdir` returns
@@ -63,20 +89,17 @@ export declare function parseUipignore(body: string): Set<string>;
63
89
  * caller provides. Directory exclusion is by exact directory name at any
64
90
  * depth. Files matching DEFAULT_EXCLUDED_FILE_PATTERNS (e.g. `.env`,
65
91
  * `.env.local`) are also skipped at any depth — they conventionally hold
66
- * credentials and must not be shipped in the bundle.
92
+ * credentials and must not be shipped in the bundle. Files and directories
93
+ * matched by `ignoreRules` (parsed `.uipignore` files) are skipped as well.
67
94
  */
68
- export declare function collectTree(fs: IFileSystem, dir: string, options?: {
69
- additionalExcludeDirs?: Iterable<string>;
70
- }): Promise<{
95
+ export declare function collectTree(fs: IFileSystem, dir: string, options?: CollectTreeOptions): Promise<{
71
96
  files: string[];
72
97
  emptyDirs: string[];
73
98
  }>;
74
99
  /**
75
100
  * Recursively collect all file paths under a directory.
76
101
  */
77
- export declare function collectFiles(fs: IFileSystem, dir: string, options?: {
78
- additionalExcludeDirs?: Iterable<string>;
79
- }): Promise<string[]>;
102
+ export declare function collectFiles(fs: IFileSystem, dir: string, options?: CollectTreeOptions): Promise<string[]>;
80
103
  /**
81
104
  * Collect all files (and empty directories) under `dir` and zip them using
82
105
  * fflate. Empty directories are written as standard zip directory records
@@ -85,9 +108,7 @@ export declare function collectFiles(fs: IFileSystem, dir: string, options?: {
85
108
  *
86
109
  * Returns the zip as a Uint8Array.
87
110
  */
88
- export declare function createZipFromDir(fs: IFileSystem, dir: string, options?: {
89
- additionalExcludeDirs?: Iterable<string>;
90
- }): Promise<Uint8Array>;
111
+ export declare function createZipFromDir(fs: IFileSystem, dir: string, options?: CollectTreeOptions): Promise<Uint8Array>;
91
112
  /**
92
113
  * Give an archive a zip64 tail once it holds more entries than the classic
93
114
  * end-of-central-directory record can count.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/solution-sdk",
3
3
  "author": "UiPath",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
- "version": "1.204.0-preview.249",
5
+ "version": "1.204.0-preview.254",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/UiPath/cli.git",
@@ -40,5 +40,5 @@
40
40
  "dist"
41
41
  ],
42
42
  "private": false,
43
- "gitHead": "a0ea4d79473cd8077d99d13c2644163be126b103"
43
+ "gitHead": "3ee79cdec05b36231a8da9e8de6bf0043585526a"
44
44
  }