@uipath/case-tool 1.204.0 → 1.205.0-preview.258

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/THIRD-PARTY-NOTICES.md +24 -11
  2. package/dist/{authoring-6ckkzfc9.js → authoring-kqh34zzm.js} +49 -30
  3. package/dist/{business-rule-export-kg5bk8aw.js → business-rule-export-ey588rv7.js} +2 -2
  4. package/dist/canvas-notes-86fxx1t8.js +19 -0
  5. package/dist/{case-api-rvamfn02.js → case-api-sme7esce.js} +6 -6
  6. package/dist/case-bindings-service-cht20gqt.js +430 -0
  7. package/dist/case-debug-solution-projects-h3w2nx0a.js +34 -0
  8. package/dist/{case-debug-studio-web-service-xxfesw4v.js → case-debug-studio-web-service-3mkrtaet.js} +16 -10
  9. package/dist/{case-described-io-service-14hdnqcc.js → case-described-io-service-dx1f4nxe.js} +37 -11
  10. package/dist/case-event-trigger-bindings-g9ftnm4x.js +16 -0
  11. package/dist/{case-format-service-yb48785t.js → case-format-service-6aew6tqc.js} +2 -2
  12. package/dist/{case-pack-service-9185h6ez.js → case-pack-service-pqq8wnfd.js} +6 -6
  13. package/dist/case-schema-version-h820ne16.js +20 -0
  14. package/dist/{case-shape-reader-mw58avr0.js → case-shape-reader-dsbraetf.js} +1 -1
  15. package/dist/{case-splice-service-tkmb7xjp.js → case-splice-service-s5gccctq.js} +53 -8
  16. package/dist/{case-validate-service-c84e2bhv.js → case-validate-service-rey6btew.js} +128 -42
  17. package/dist/{connector-enrichment-service-hfv0kwht.js → connector-enrichment-service-crqs2216.js} +23 -20
  18. package/dist/{connector-lookup-service-whgjceyj.js → connector-lookup-service-dwv8q5eh.js} +6 -6
  19. package/dist/connector-task-shape-mpazkf7s.js +14 -0
  20. package/dist/{connector-task-spec-k0cwavrm.js → connector-task-spec-trs4tcb3.js} +196 -40
  21. package/dist/{de-MUJPA4EB-dpg7t2rw.js → de-UZI7FJDO-mwvc4cxe.js} +29 -2
  22. package/dist/{de-FGHEJRCI-rv513mfh.js → de-WLW6KWOJ-2qnsqdtw.js} +238 -31
  23. package/dist/{debug-service-ch3v6jmm.js → debug-service-7q98j726.js} +3 -3
  24. package/dist/{embedded-file-reader-v8c2yj2a.js → embedded-file-reader-r66242ey.js} +2 -2
  25. package/dist/{en-FBPVNKFN-dqt573xn.js → en-EJCBA3LK-dtpdghgj.js} +12 -4
  26. package/dist/{en-BWGKA5OE-1qkvb9rn.js → en-M7GQYBV2-5nfmpnfz.js} +88 -6
  27. package/dist/{enrichment-service-3f1kygjs.js → enrichment-service-hv7ff88p.js} +56 -12
  28. package/dist/{es-7SE7HX2X-8yh1aj2y.js → es-4UBUTCQA-m1ytpyx2.js} +29 -2
  29. package/dist/{es-KR3ZSNMP-84zphx0x.js → es-5THCNRFN-tqwyrdgy.js} +235 -28
  30. package/dist/{es-MX-2MYFZU7X-3rek4r73.js → es-MX-5RELIXKI-9jhqtddc.js} +29 -2
  31. package/dist/{es-MX-XXZJGC4R-2mr8jtgm.js → es-MX-TWZBRAXK-gqd9swzw.js} +237 -30
  32. package/dist/filter-engine-7ep90g7f.js +11 -0
  33. package/dist/{fr-Y6NPVODW-8vr1ja4b.js → fr-CERONSRC-edpxhbmb.js} +237 -30
  34. package/dist/{fr-MDFKNZ4C-h4a122k9.js → fr-VBM5WRC2-63z7w4mh.js} +29 -2
  35. package/dist/index-332n0kxj.js +282 -0
  36. package/dist/{index-wmffgzmr.js → index-5dxh9z60.js} +21751 -11098
  37. package/dist/{index-aw2gqqat.js → index-a2fvrrth.js} +4 -4
  38. package/dist/{index-4yanx3rn.js → index-ekwtgx7y.js} +1089 -218
  39. package/dist/{index-ng2f77my.js → index-fyc0k5dd.js} +985 -617
  40. package/dist/index-n9qvnx4x.js +29 -0
  41. package/dist/{index-hhsf00x8.js → index-ngs0a2he.js} +1 -1
  42. package/dist/{index-j2r3jb6c.js → index-xq6ajhgq.js} +2 -2
  43. package/dist/index.js +12 -12
  44. package/dist/init-entry-points-hhpv3e3f.js +98 -0
  45. package/dist/{input-reader-1tcqt27f.js → input-reader-c7wz8ra2.js} +3 -3
  46. package/dist/{ja-UTQEAP34-8e0q6swp.js → ja-43QL7CGO-c3q8gre9.js} +29 -2
  47. package/dist/{ja-Q5PXKJ2V-p4msxzjd.js → ja-U2MCNHGT-gz0ap1jk.js} +235 -28
  48. package/dist/{known-types-0h9kqwyy.js → known-types-jvkdgmzz.js} +5 -4
  49. package/dist/{ko-AXCHW2OK-askct7f6.js → ko-TLL6Z6CD-wrt3n8a9.js} +29 -2
  50. package/dist/{ko-AYBDSRZG-41mdmsg1.js → ko-XAUYQWDR-zp81gjp4.js} +237 -30
  51. package/dist/localSolutionDiscovery-yyx234ak.js +13 -0
  52. package/dist/migration-diagnosis-ns5cw4e3.js +99 -0
  53. package/dist/{node-strategy-5pz40tee.js → node-strategy-v442hwgd.js} +1 -1
  54. package/dist/node-sync-service-1wkcyn1n.js +57 -0
  55. package/dist/out-target-wjgmna0r.js +111 -0
  56. package/dist/{packager-tool-85q4f3pq.js → packager-tool-1pcmxqny.js} +3 -3
  57. package/dist/{packager-tool-8a9yqfq7.js → packager-tool-1yfw674x.js} +4 -2
  58. package/dist/{packager-tool-pdhhzfr5.js → packager-tool-29x6vran.js} +296 -417
  59. package/dist/packager-tool-2sn7d8fd.js +41 -0
  60. package/dist/packager-tool-4p11fvf4.js +92 -0
  61. package/dist/{packager-tool-25hng8h4.js → packager-tool-4rtktkhv.js} +16211 -13084
  62. package/dist/{packager-tool-yfm83bzd.js → packager-tool-67vy1fz3.js} +4 -3
  63. package/dist/{packager-tool-d88rqwk8.js → packager-tool-6z1hsm2h.js} +13 -5
  64. package/dist/packager-tool-7hw344bt.js +107 -0
  65. package/dist/{packager-tool-3q3d1hk8.js → packager-tool-83v804p7.js} +56 -6
  66. package/dist/{packager-tool-00y70spr.js → packager-tool-87y6xw3a.js} +2 -1
  67. package/dist/packager-tool-93mdeqay.js +18 -0
  68. package/dist/{packager-tool-64rg5ekd.js → packager-tool-9e59z4d6.js} +75 -7
  69. package/dist/{packager-tool-vepqrsse.js → packager-tool-9kf3fqtr.js} +2 -2
  70. package/dist/packager-tool-9kvkzc05.js +74 -0
  71. package/dist/{packager-tool-s6619wtx.js → packager-tool-9sd483vs.js} +2 -2
  72. package/dist/{packager-tool-f78ntj5g.js → packager-tool-9y1w2wds.js} +51 -6
  73. package/dist/packager-tool-a17g0pj1.js +62 -0
  74. package/dist/{packager-tool-167qap9m.js → packager-tool-aagnvyba.js} +845 -38
  75. package/dist/{packager-tool-0p6dbsp0.js → packager-tool-c5q10254.js} +5 -5
  76. package/dist/{packager-tool-wj9d9mqe.js → packager-tool-e15kqpyh.js} +12 -13
  77. package/dist/{packager-tool-c31qx8kc.js → packager-tool-ezds6t5e.js} +2 -2
  78. package/dist/{packager-tool-d3zvghjd.js → packager-tool-f2z2dscy.js} +308 -120
  79. package/dist/{packager-tool-hvzjm2nk.js → packager-tool-f8vwy92w.js} +2093 -5805
  80. package/dist/{packager-tool-rgpdaxbx.js → packager-tool-gx2cer6a.js} +5385 -1098
  81. package/dist/{packager-tool-xdxr3ync.js → packager-tool-hdxtgckw.js} +11 -1
  82. package/dist/{packager-tool-mr149jsw.js → packager-tool-k5cpxdm4.js} +17 -7
  83. package/dist/packager-tool-k6jbedyc.js +69 -0
  84. package/dist/packager-tool-kdhey8gz.js +153 -0
  85. package/dist/{packager-tool-cenvh23g.js → packager-tool-kyrm4e5m.js} +718 -87
  86. package/dist/packager-tool-mqy97y5f.js +52 -0
  87. package/dist/{packager-tool-jfysbxdt.js → packager-tool-mzf4gmph.js} +4 -4
  88. package/dist/packager-tool-n7w9wx62.js +25 -0
  89. package/dist/{packager-tool-7q6z6npd.js → packager-tool-pcvhcn2k.js} +93 -11
  90. package/dist/packager-tool-r0x3qh59.js +307 -0
  91. package/dist/{packager-tool-w1b5pyj6.js → packager-tool-r6b5ktzb.js} +730 -14
  92. package/dist/{packager-tool-zbrda9sn.js → packager-tool-rk25wp3c.js} +1 -1
  93. package/dist/{packager-tool-xcd87qyx.js → packager-tool-v2kcgjbf.js} +2 -3
  94. package/dist/{case-bindings-service-d9vezn69.js → packager-tool-wekqkmgn.js} +20 -231
  95. package/dist/packager-tool-yct6zp4m.js +335 -0
  96. package/dist/{packager-tool-kpqr938m.js → packager-tool-ydyvtknp.js} +26 -3
  97. package/dist/{packager-tool-v99ygh9f.js → packager-tool-yn33pw57.js} +124 -58
  98. package/dist/{packager-tool-4rqd21wc.js → packager-tool-yn7r7zq2.js} +19 -5
  99. package/dist/{packager-tool-cmwets3m.js → packager-tool-zf8f9pmm.js} +1 -1
  100. package/dist/packager-tool.js +3 -3
  101. package/dist/{project-artifacts-rng5m6r2.js → project-artifacts-bgyyb0dm.js} +1 -1
  102. package/dist/{pt-BR-TKHNHMET-sn91xyq0.js → pt-BR-GNQNAAZ2-xadharv4.js} +237 -30
  103. package/dist/{pt-BR-Y6K6XHXK-mp3hwhw1.js → pt-BR-USP2T7GD-pedn77m1.js} +29 -2
  104. package/dist/{pt-3DIO5QWG-59b3f4bc.js → pt-RMIAKZB4-67enhx3m.js} +29 -2
  105. package/dist/{pt-ROXU257Y-2f6bxev4.js → pt-TO2DARY2-ftcce1bv.js} +237 -30
  106. package/dist/{resolved-check-p99hysaw.js → resolved-check-aqw7568y.js} +1 -1
  107. package/dist/{resourcesSyncService-zwjyp1qx.js → resourcesSyncService-d302jnap.js} +32 -170
  108. package/dist/{ro-BWR3ONRR-vzx3hy8a.js → ro-GHOBYW2S-mhnqsgaa.js} +29 -2
  109. package/dist/{ro-AVAWPKOO-b89pw79r.js → ro-WUYJV6OW-a8d9qy1n.js} +235 -28
  110. package/dist/{sdd-convert-service-vf0ps358.js → sdd-convert-service-8jpew7vz.js} +686 -445
  111. package/dist/{sdd-lookup-dwzpvvwn.js → sdd-lookup-fe900sdb.js} +2 -2
  112. package/dist/{sdd-resolve-service-mjqad2nn.js → sdd-resolve-service-qdtmxw9b.js} +38 -13
  113. package/dist/sdd-resolve-siblings-6kfxc2t6.js +53 -0
  114. package/dist/{solution-auth-kddmbm0p.js → solution-auth-30yycqtv.js} +3 -3
  115. package/dist/solution-discovery-g6ksnrg1.js +38 -0
  116. package/dist/{strict-case-rules-tz37bspw.js → strict-case-rules-4tjcaznr.js} +3 -2
  117. package/dist/{strict-entry-points-v14d7y50.js → strict-entry-points-g2pd4mf4.js} +29 -1
  118. package/dist/{strict-sdd-audit-4aqdeh59.js → strict-sdd-audit-q7tb9yj7.js} +7 -5
  119. package/dist/task-type-declaration-7a8fqdvs.js +46 -0
  120. package/dist/tool.js +12 -12
  121. package/dist/{tr-5IIHSFW5-hw4cewew.js → tr-GDTLECMM-k5fhmq13.js} +29 -2
  122. package/dist/{tr-JMIP7ZSL-c39b6pe4.js → tr-M3F5A6AU-bb0tg39m.js} +235 -28
  123. package/dist/{trigger-enrichment-service-g3vt051f.js → trigger-enrichment-service-sj0p2d1j.js} +23 -20
  124. package/dist/trigger-entry-point-id-yhqwnkx9.js +15 -0
  125. package/dist/{zh-CN-IFFXSEJS-9wm9gmrv.js → zh-CN-C5G4PC7C-ds9gkptg.js} +235 -28
  126. package/dist/{zh-CN-R2KU4U5L-tc1hat59.js → zh-CN-I5D7WHBD-sr5h0a98.js} +29 -2
  127. package/dist/{zh-TW-GNKMELBF-j674515r.js → zh-TW-2AVLM723-288pkc1z.js} +29 -2
  128. package/dist/{zh-TW-IYBNYAMG-8727c7v2.js → zh-TW-62HZIG6O-787kdwex.js} +234 -27
  129. package/package.json +2 -2
  130. package/dist/migration-diagnosis-ag2sgd1e.js +0 -71
  131. package/dist/node-sync-service-2tfrgbjs.js +0 -36
  132. package/dist/out-target-jakehnd3.js +0 -70
  133. package/dist/packager-tool-57pzrd0g.js +0 -32
  134. package/dist/packager-tool-dthjwajc.js +0 -13
  135. package/dist/packager-tool-xy04yy0v.js +0 -32
@@ -1,6 +1,15 @@
1
+ import {
2
+ UsersApi,
3
+ createApiClient
4
+ } from "./packager-tool-f8vwy92w.js";
5
+ import {
6
+ findSolutionFileUpward,
7
+ normalizeProjectType,
8
+ toPortableRelativePath
9
+ } from "./packager-tool-67vy1fz3.js";
1
10
  import {
2
11
  getSolutionAuthContext
3
- } from "./packager-tool-zbrda9sn.js";
12
+ } from "./packager-tool-rk25wp3c.js";
4
13
  import {
5
14
  JsonSerializerFactory,
6
15
  JsonSerializerNames,
@@ -10,20 +19,11 @@ import {
10
19
  import {
11
20
  FirstPartyServiceApi
12
21
  } from "./packager-tool-53w8skv5.js";
13
- import {
14
- UsersApi,
15
- createApiClient
16
- } from "./packager-tool-hvzjm2nk.js";
17
- import {
18
- findSolutionFileUpward,
19
- normalizeProjectType,
20
- toPortableRelativePath
21
- } from "./packager-tool-yfm83bzd.js";
22
- import"./packager-tool-4rqd21wc.js";
22
+ import"./packager-tool-yn7r7zq2.js";
23
23
  import"./packager-tool-b098y4a2.js";
24
24
  import {
25
25
  getLoginStatusAsync
26
- } from "./packager-tool-v99ygh9f.js";
26
+ } from "./packager-tool-yn33pw57.js";
27
27
  import"./packager-tool-0gctz400.js";
28
28
  import"./packager-tool-qa9gftnj.js";
29
29
  import"./packager-tool-yc4kw997.js";
@@ -32,10 +32,10 @@ import {
32
32
  extractErrorMessage,
33
33
  isGuid,
34
34
  logger
35
- } from "./packager-tool-3q3d1hk8.js";
35
+ } from "./packager-tool-83v804p7.js";
36
36
  import {
37
37
  getFileSystem
38
- } from "./packager-tool-xdxr3ync.js";
38
+ } from "./packager-tool-hdxtgckw.js";
39
39
  import {
40
40
  __commonJS,
41
41
  __require,
@@ -2474,6 +2474,19 @@ class NullSecretsProvider {
2474
2474
  }
2475
2475
  }
2476
2476
 
2477
+ // ../../node_modules/@uipath/resource-builder-sdk/dist/providers/feature-flag-provider.js
2478
+ class NullFeatureFlagProvider {
2479
+ getBool(_featureFlagName, defaultValue) {
2480
+ return defaultValue ?? false;
2481
+ }
2482
+ getInt(_featureFlagName, defaultValue) {
2483
+ return defaultValue ?? 0;
2484
+ }
2485
+ getString(_featureFlagName, defaultValue) {
2486
+ return defaultValue ?? "";
2487
+ }
2488
+ }
2489
+
2477
2490
  // ../../node_modules/@uipath/resource-builder-sdk/dist/exceptions/timeout-exception.js
2478
2491
  class TimeoutException extends Error {
2479
2492
  constructor(message, timeoutMs) {
@@ -2628,10 +2641,12 @@ function withFileOperationTimeout2(provider, timeoutMs) {
2628
2641
  // ../../node_modules/@uipath/resource-builder-sdk/dist/solution/solution-context-options.js
2629
2642
  var DEFAULT_SOLUTION_CONTEXT_OPTIONS = {
2630
2643
  lockTimeoutMs: 30000,
2631
- fileOperationTimeoutMs: 30000
2644
+ fileOperationTimeoutMs: 30000,
2645
+ maxDegreeOfParallelism: 1
2632
2646
  };
2633
2647
  var SOLUTION_CONTEXT_TIMEOUT_STORAGE_KEY = "SOL_RB_SOLUTION_CONTEXT_TIMEOUT_MS";
2634
2648
  var FILE_OPERATION_TIMEOUT_STORAGE_KEY = "SOL_RB_FILE_OPERATION_TIMEOUT_MS";
2649
+ var MAX_DEGREE_OF_PARALLELISM_STORAGE_KEY = "SOL_RB_MAX_DEGREE_OF_PARALLELISM";
2635
2650
  function resolveTimeoutMs(storageKey, configured, fallback) {
2636
2651
  const override = readTimeoutOverrideMs(storageKey);
2637
2652
  if (override !== undefined)
@@ -2644,10 +2659,33 @@ function resolveLockTimeoutMs(options) {
2644
2659
  function resolveFileOperationTimeoutMs(options) {
2645
2660
  return resolveTimeoutMs(FILE_OPERATION_TIMEOUT_STORAGE_KEY, options?.fileOperationTimeoutMs, DEFAULT_SOLUTION_CONTEXT_OPTIONS.fileOperationTimeoutMs);
2646
2661
  }
2662
+ function isValidDegreeOfParallelism(value) {
2663
+ return typeof value == "number" && Number.isInteger(value) && value > 0;
2664
+ }
2665
+ function resolveMaxDegreeOfParallelism(options) {
2666
+ const override = readDegreeOfParallelismOverride(MAX_DEGREE_OF_PARALLELISM_STORAGE_KEY);
2667
+ if (override !== undefined)
2668
+ return override;
2669
+ return isValidDegreeOfParallelism(options?.maxDegreeOfParallelism) ? options.maxDegreeOfParallelism : DEFAULT_SOLUTION_CONTEXT_OPTIONS.maxDegreeOfParallelism;
2670
+ }
2671
+ function readDegreeOfParallelismOverride(storageKey) {
2672
+ try {
2673
+ if ("u" < typeof localStorage)
2674
+ return;
2675
+ const raw = localStorage.getItem(storageKey);
2676
+ if (raw === null || raw.trim() === "")
2677
+ return;
2678
+ const parsed = Number(raw);
2679
+ return isValidDegreeOfParallelism(parsed) ? parsed : undefined;
2680
+ } catch {
2681
+ return;
2682
+ }
2683
+ }
2647
2684
  function mergeSolutionContextOptions(options) {
2648
2685
  return {
2649
2686
  lockTimeoutMs: isValidTimeoutMs(options?.lockTimeoutMs) ? options.lockTimeoutMs : DEFAULT_SOLUTION_CONTEXT_OPTIONS.lockTimeoutMs,
2650
- fileOperationTimeoutMs: isValidTimeoutMs(options?.fileOperationTimeoutMs) ? options.fileOperationTimeoutMs : DEFAULT_SOLUTION_CONTEXT_OPTIONS.fileOperationTimeoutMs
2687
+ fileOperationTimeoutMs: isValidTimeoutMs(options?.fileOperationTimeoutMs) ? options.fileOperationTimeoutMs : DEFAULT_SOLUTION_CONTEXT_OPTIONS.fileOperationTimeoutMs,
2688
+ maxDegreeOfParallelism: isValidDegreeOfParallelism(options?.maxDegreeOfParallelism) ? options.maxDegreeOfParallelism : DEFAULT_SOLUTION_CONTEXT_OPTIONS.maxDegreeOfParallelism
2651
2689
  };
2652
2690
  }
2653
2691
 
@@ -3438,6 +3476,16 @@ function getRootFolder(solution) {
3438
3476
  }
3439
3477
 
3440
3478
  // ../../node_modules/@uipath/resource-builder-sdk/dist/solution/multi-file-solution-definition-provider.js
3479
+ function nowMs() {
3480
+ return globalThis.performance?.now?.() ?? Date.now();
3481
+ }
3482
+ function round1(ms) {
3483
+ return Math.round(10 * ms) / 10;
3484
+ }
3485
+ function cancellationError(signal) {
3486
+ return signal?.reason instanceof OperationCancelledException ? signal.reason : new OperationCancelledException;
3487
+ }
3488
+
3441
3489
  class MultiFileSolutionDefinitionProvider {
3442
3490
  get caseInsensitiveSerializer() {
3443
3491
  if (!this._caseInsensitiveSerializer)
@@ -3455,137 +3503,344 @@ class MultiFileSolutionDefinitionProvider {
3455
3503
  }
3456
3504
  async readAsync(context, cancellationToken) {
3457
3505
  this.logger.info("Reading multi-file solution definition for solution %s", context.path);
3458
- const solutionKey = this.getSolutionKey(context);
3459
- const fileStorageProvider = await this.getFileStorageProviderAsync(context, cancellationToken);
3460
- const resources = [];
3461
- const solutionFiles = [];
3462
- let hashes;
3463
- let paths;
3464
- const pathsByKind = this.getPathsByKind(context);
3465
- let tree;
3466
- pathsByKind.clear();
3506
+ const loadStarted = nowMs();
3507
+ let fileCount = 0;
3508
+ let listMs = 0;
3509
+ let readStarted = loadStarted;
3510
+ let readWallMs = 0;
3511
+ let readCompleted = false;
3512
+ let ioMs = 0;
3513
+ let maxFileIoMs = 0;
3514
+ let parseMs = 0;
3515
+ let hashMs = 0;
3516
+ let chars = 0;
3517
+ let loadedCount = 0;
3467
3518
  const parseErrors = [];
3468
3519
  const missingFiles = [];
3469
3520
  const invalidFiles = [];
3470
- context.items[SolutionContextKeys.PARSE_ERRORS_ITEM_KEY] = parseErrors;
3471
- if (!context.isReadOnly) {
3472
- hashes = this.getHashes(context);
3473
- paths = this.getPaths(context);
3474
- tree = this.getTree(context);
3475
- hashes.clear();
3476
- paths.clear();
3477
- tree.length = 0;
3478
- }
3479
- const resourceFiles = await fileStorageProvider.getFilesAsync(SolutionConstants.RESOURCE_FILES_FOLDER_NAME, "*.json", cancellationToken);
3480
- for (const resourceFile of resourceFiles)
3481
- try {
3482
- const stream = await fileStorageProvider.openFileAsync(resourceFile, cancellationToken);
3483
- const content = await this.streamToString(stream);
3484
- const wrapper = this.caseInsensitiveSerializer.deserialize(content);
3485
- if (wrapper?.resource) {
3486
- const rd = this.fromSerializable(wrapper.resource, solutionFiles);
3487
- const relPath = resourceFile.replace(/\\/g, "/");
3488
- const segments = relPath.split("/").filter((s) => s.length > 0);
3489
- const firstSegment = segments[0];
3490
- if (segments.length >= 3 && firstSegment && firstSegment.toLowerCase() === SolutionConstants.RESOURCE_FILES_FOLDER_NAME.toLowerCase()) {
3491
- const hasType = !!rd.type;
3492
- const folderSegmentCount = hasType ? segments.length - 3 : segments.length - 2;
3493
- if (folderSegmentCount < 1)
3494
- rd.folders = [
3495
- {
3496
- fullyQualifiedName: SolutionConstants.ROOT_FOLDER_NAME
3497
- }
3498
- ];
3499
- else {
3500
- const segmentsToUse = segments.slice(1, folderSegmentCount);
3501
- const folderFqn = segmentsToUse.join("/");
3502
- rd.folders = [
3503
- {
3504
- fullyQualifiedName: folderFqn
3505
- }
3506
- ];
3521
+ let metricsLogged = false;
3522
+ const logReadMetrics = (outcome) => {
3523
+ metricsLogged = true;
3524
+ const totalMs = nowMs() - loadStarted;
3525
+ const mergeMs = readCompleted ? nowMs() - readStarted - readWallMs : 0;
3526
+ const metrics = {
3527
+ outcome,
3528
+ path: context.path,
3529
+ fileCount,
3530
+ totalMs: round1(totalMs),
3531
+ listMs: round1(listMs),
3532
+ readWallMs: round1(readWallMs),
3533
+ ioMs: round1(ioMs),
3534
+ maxFileIoMs: round1(maxFileIoMs),
3535
+ parseMs: round1(parseMs),
3536
+ hashMs: round1(hashMs),
3537
+ mergeMs: round1(mergeMs),
3538
+ chars,
3539
+ degreeOfParallelism: resolveMaxDegreeOfParallelism(this.options),
3540
+ isReadOnly: context.isReadOnly,
3541
+ loaded: loadedCount,
3542
+ missing: missingFiles.length,
3543
+ invalid: invalidFiles.length,
3544
+ parseErrors: parseErrors.length
3545
+ };
3546
+ const message = `Solution read ${outcome} for solution ${context.path}: ${metrics.fileCount} files in ${metrics.totalMs} ms (list ${metrics.listMs} ms, read ${metrics.readWallMs} ms wall, io ${metrics.ioMs} ms summed, max file io ${metrics.maxFileIoMs} ms, parse ${metrics.parseMs} ms, hash ${metrics.hashMs} ms, merge ${metrics.mergeMs} ms); ${metrics.chars} chars; parallelism ${metrics.degreeOfParallelism}; readOnly ${metrics.isReadOnly}; loaded ${metrics.loaded}, missing ${metrics.missing}, invalid ${metrics.invalid}, parseErrors ${metrics.parseErrors}`;
3547
+ if (outcome === "Success")
3548
+ this.logger.info(message, metrics);
3549
+ else
3550
+ this.logger.warn(message, metrics);
3551
+ };
3552
+ const readCore = async () => {
3553
+ const solutionKey = this.getSolutionKey(context);
3554
+ const fileStorageProvider = await this.getFileStorageProviderAsync(context, cancellationToken);
3555
+ const resources = [];
3556
+ const solutionFiles = [];
3557
+ let hashes;
3558
+ let paths;
3559
+ const pathsByKind = this.getPathsByKind(context);
3560
+ let tree;
3561
+ pathsByKind.clear();
3562
+ context.items[SolutionContextKeys.PARSE_ERRORS_ITEM_KEY] = parseErrors;
3563
+ if (!context.isReadOnly) {
3564
+ hashes = this.getHashes(context);
3565
+ paths = this.getPaths(context);
3566
+ tree = this.getTree(context);
3567
+ hashes.clear();
3568
+ paths.clear();
3569
+ tree.length = 0;
3570
+ }
3571
+ const listStarted = nowMs();
3572
+ const resourceFiles = await fileStorageProvider.getFilesAsync(SolutionConstants.RESOURCE_FILES_FOLDER_NAME, "*.json", cancellationToken);
3573
+ listMs = nowMs() - listStarted;
3574
+ fileCount = resourceFiles.length;
3575
+ readStarted = nowMs();
3576
+ const readResults = await this.readResourceFilesAsync(context, fileStorageProvider, resourceFiles, cancellationToken);
3577
+ readWallMs = nowMs() - readStarted;
3578
+ readCompleted = true;
3579
+ let fatal;
3580
+ let hasFatal = false;
3581
+ for (const result of readResults)
3582
+ if (result !== undefined) {
3583
+ if (result.timings) {
3584
+ ioMs += result.timings.ioMs;
3585
+ maxFileIoMs = Math.max(maxFileIoMs, result.timings.ioMs);
3586
+ parseMs += result.timings.parseMs;
3587
+ hashMs += result.timings.hashMs;
3588
+ chars += result.timings.chars;
3589
+ }
3590
+ if (result.fatal !== undefined) {
3591
+ if (!hasFatal) {
3592
+ fatal = result.fatal;
3593
+ hasFatal = true;
3507
3594
  }
3508
- } else
3509
- rd.folders = [
3510
- {
3511
- fullyQualifiedName: SolutionConstants.ROOT_FOLDER_NAME
3595
+ continue;
3596
+ }
3597
+ if (!hasFatal)
3598
+ switch (result.outcome) {
3599
+ case "loaded": {
3600
+ loadedCount++;
3601
+ const rd = result.resource;
3602
+ for (const file of result.files)
3603
+ if (!solutionFiles.some((sf) => sf.name === file.name && sf.kind === file.kind))
3604
+ solutionFiles.push(file);
3605
+ resources.push(rd);
3606
+ const resourceKey = rd.key;
3607
+ const normalizedFullPath = result.normalizedPath;
3608
+ if (!pathsByKind.has(rd.kind))
3609
+ pathsByKind.set(rd.kind, []);
3610
+ const kindPaths = pathsByKind.get(rd.kind);
3611
+ if (kindPaths)
3612
+ kindPaths.push({
3613
+ name: rd.name,
3614
+ key: rd.key,
3615
+ path: normalizedFullPath
3616
+ });
3617
+ if (!context.isReadOnly && hashes && paths) {
3618
+ paths.set(resourceKey, normalizedFullPath);
3619
+ hashes.set(resourceKey, result.hash);
3620
+ }
3621
+ break;
3512
3622
  }
3513
- ];
3514
- resources.push(rd);
3515
- const resourceKey = rd.key;
3516
- const normalizedFullPath = this.getNormalizedPath(resourceFile);
3517
- if (!pathsByKind.has(rd.kind))
3518
- pathsByKind.set(rd.kind, []);
3519
- const kindPaths = pathsByKind.get(rd.kind);
3520
- if (kindPaths)
3521
- kindPaths.push({
3522
- name: rd.name,
3523
- key: rd.key,
3524
- path: normalizedFullPath
3623
+ case "missing":
3624
+ missingFiles.push(result.file);
3625
+ break;
3626
+ case "invalid":
3627
+ invalidFiles.push(result.file);
3628
+ break;
3629
+ case "parseError":
3630
+ parseErrors.push(result.file);
3631
+ break;
3632
+ }
3633
+ }
3634
+ if (hasFatal) {
3635
+ logReadMetrics("Fatal");
3636
+ throw fatal;
3637
+ }
3638
+ if (missingFiles.length > 0) {
3639
+ logReadMetrics("MissingFiles");
3640
+ throw new BadRequestException(ErrorCodes.Resources.MissingFileDependencies, `Solution has missing files: ${missingFiles.join(", ")}`);
3641
+ }
3642
+ if (invalidFiles.length > 0) {
3643
+ logReadMetrics("InvalidFiles");
3644
+ throw new BadRequestException(ErrorCodes.Resources.InvalidResourceFile, `Solution has resource files with invalid content: ${invalidFiles.join(", ")}`);
3645
+ }
3646
+ if (parseErrors.length > 0) {
3647
+ logReadMetrics("ParseErrors");
3648
+ throw new Error(`Failed to read resource files for solution ${context.path}: ${parseErrors.join(", ")}`);
3649
+ }
3650
+ const folderMap = new Map;
3651
+ const rootFolder = this.buildRootFolder(solutionKey, SolutionConstants.ROOT_FOLDER_NAME);
3652
+ folderMap.set(rootFolder.fullyQualifiedName.toLowerCase(), rootFolder);
3653
+ for (const res of resources)
3654
+ for (const fdep of res.folders ?? []) {
3655
+ const fqnLower = fdep.fullyQualifiedName.toLowerCase();
3656
+ if (!folderMap.has(fqnLower)) {
3657
+ const folderKey = this.generateGuidFromString(fdep.fullyQualifiedName);
3658
+ const pathSegments = fdep.fullyQualifiedName.split("/").filter((s) => s.length > 0).map((p) => {
3659
+ if (p.toLowerCase() !== SolutionConstants.ROOT_FOLDER_NAME.toLowerCase())
3660
+ return this.generateGuidFromString(SolutionConstants.ROOT_FOLDER_NAME);
3661
+ return rootFolder.key;
3662
+ });
3663
+ const folderPath = pathSegments.join(".");
3664
+ folderMap.set(fqnLower, {
3665
+ key: folderKey,
3666
+ fullyQualifiedName: fdep.fullyQualifiedName,
3667
+ path: folderPath
3525
3668
  });
3526
- if (!context.isReadOnly && hashes && paths) {
3527
- paths.set(resourceKey, normalizedFullPath);
3528
- hashes.set(resourceKey, await this.computeHash(content));
3529
3669
  }
3530
- } else {
3531
- this.logger.error("Failed to read resource file %s for solution %s: invalid content", undefined, resourceFile, context.path);
3532
- invalidFiles.push(resourceFile);
3533
- }
3534
- } catch (ex) {
3535
- if (ex instanceof OperationCancelledException || cancellationToken?.aborted) {
3536
- this.logger.warn("Operation cancelled while reading file %s for solution %s", resourceFile, context.path);
3537
- throw ex instanceof OperationCancelledException ? ex : new OperationCancelledException;
3538
- }
3539
- if (ex instanceof TimeoutException)
3540
- throw new TimeoutException(`Reading resource file ${resourceFile} for solution ${context.path} timed out: ${ex.message}`, ex.timeoutMs);
3541
- if (isFileNotFoundError(ex)) {
3542
- this.logger.warn("Resource file listed but missing in storage for solution %s: %s", resourceFile, context.path);
3543
- missingFiles.push(resourceFile);
3544
- } else {
3545
- this.logger.error("Failed to read resource file %s for solution %s", ex, resourceFile, context.path);
3546
- parseErrors.push(resourceFile);
3547
3670
  }
3671
+ const solution = {
3672
+ key: solutionKey,
3673
+ docVersion: SolutionConstants.CURRENT_DOC_VERSION,
3674
+ folders: Array.from(folderMap.values()),
3675
+ resources,
3676
+ files: solutionFiles
3677
+ };
3678
+ await this.replaceDuplicateKeysAsync(solution, cancellationToken);
3679
+ if (!context.isReadOnly && tree) {
3680
+ const orderedResourceKeys = getTopologicalIdsOrdering(buildDependencyGraph(solution.resources));
3681
+ tree.push(...orderedResourceKeys);
3548
3682
  }
3549
- if (missingFiles.length > 0)
3550
- throw new BadRequestException(ErrorCodes.Resources.MissingFileDependencies, `Solution has missing files: ${missingFiles.join(", ")}`);
3551
- if (invalidFiles.length > 0)
3552
- throw new BadRequestException(ErrorCodes.Resources.InvalidResourceFile, `Solution has resource files with invalid content: ${invalidFiles.join(", ")}`);
3553
- if (parseErrors.length > 0)
3554
- throw new Error(`Failed to read resource files for solution ${context.path}: ${parseErrors.join(", ")}`);
3555
- const folderMap = new Map;
3556
- const rootFolder = this.buildRootFolder(solutionKey, SolutionConstants.ROOT_FOLDER_NAME);
3557
- folderMap.set(rootFolder.fullyQualifiedName.toLowerCase(), rootFolder);
3558
- for (const res of resources)
3559
- for (const fdep of res.folders ?? []) {
3560
- const fqnLower = fdep.fullyQualifiedName.toLowerCase();
3561
- if (!folderMap.has(fqnLower)) {
3562
- const folderKey = this.generateGuidFromString(fdep.fullyQualifiedName);
3563
- const pathSegments = fdep.fullyQualifiedName.split("/").filter((s) => s.length > 0).map((p) => {
3564
- if (p.toLowerCase() !== SolutionConstants.ROOT_FOLDER_NAME.toLowerCase())
3565
- return this.generateGuidFromString(SolutionConstants.ROOT_FOLDER_NAME);
3566
- return rootFolder.key;
3567
- });
3568
- const folderPath = pathSegments.join(".");
3569
- folderMap.set(fqnLower, {
3570
- key: folderKey,
3571
- fullyQualifiedName: fdep.fullyQualifiedName,
3572
- path: folderPath
3573
- });
3574
- }
3683
+ logReadMetrics("Success");
3684
+ return solution;
3685
+ };
3686
+ try {
3687
+ return await readCore();
3688
+ } catch (ex) {
3689
+ if (!metricsLogged)
3690
+ logReadMetrics("Fatal");
3691
+ throw ex;
3692
+ }
3693
+ }
3694
+ async readResourceFilesAsync(context, fileStorageProvider, resourceFiles, cancellationToken) {
3695
+ const results = Array.from({
3696
+ length: resourceFiles.length
3697
+ }, () => {
3698
+ return;
3699
+ });
3700
+ if (resourceFiles.length === 0)
3701
+ return results;
3702
+ const computeHash = !context.isReadOnly;
3703
+ const degreeOfParallelism = Math.min(resolveMaxDegreeOfParallelism(this.options), resourceFiles.length);
3704
+ let nextIndex = 0;
3705
+ let stopRequested = false;
3706
+ const runWorkerAsync = async () => {
3707
+ while (!stopRequested && nextIndex < resourceFiles.length) {
3708
+ const index = nextIndex++;
3709
+ const resourceFile = resourceFiles[index];
3710
+ const result = await this.readResourceFileAsync(context, fileStorageProvider, resourceFile, computeHash, cancellationToken);
3711
+ results[index] = result;
3712
+ if (result.fatal !== undefined)
3713
+ stopRequested = true;
3575
3714
  }
3576
- const solution = {
3577
- key: solutionKey,
3578
- docVersion: SolutionConstants.CURRENT_DOC_VERSION,
3579
- folders: Array.from(folderMap.values()),
3580
- resources,
3581
- files: solutionFiles
3582
3715
  };
3583
- await this.replaceDuplicateKeysAsync(solution, cancellationToken);
3584
- if (!context.isReadOnly && tree) {
3585
- const orderedResourceKeys = getTopologicalIdsOrdering(buildDependencyGraph(solution.resources));
3586
- tree.push(...orderedResourceKeys);
3716
+ const workers = [];
3717
+ for (let i = 0;i < degreeOfParallelism; i++)
3718
+ workers.push(runWorkerAsync());
3719
+ await Promise.all(workers);
3720
+ if (cancellationToken?.aborted && !results.some((result) => result?.fatal !== undefined))
3721
+ throw cancellationError(cancellationToken);
3722
+ return results;
3723
+ }
3724
+ async readResourceFileAsync(context, fileStorageProvider, resourceFile, computeHash, cancellationToken) {
3725
+ const started = nowMs();
3726
+ let ioMs;
3727
+ let content;
3728
+ const failureTimings = () => {
3729
+ const elapsed = nowMs() - started;
3730
+ return ioMs === undefined ? {
3731
+ ioMs: elapsed,
3732
+ parseMs: 0,
3733
+ hashMs: 0,
3734
+ chars: 0
3735
+ } : {
3736
+ ioMs,
3737
+ parseMs: elapsed - ioMs,
3738
+ hashMs: 0,
3739
+ chars: content?.length ?? 0
3740
+ };
3741
+ };
3742
+ try {
3743
+ if (cancellationToken?.aborted)
3744
+ throw cancellationError(cancellationToken);
3745
+ const stream = await fileStorageProvider.openFileAsync(resourceFile, cancellationToken);
3746
+ content = await this.streamToString(stream);
3747
+ ioMs = nowMs() - started;
3748
+ const parseStarted = nowMs();
3749
+ const wrapper = this.caseInsensitiveSerializer.deserialize(content);
3750
+ if (!wrapper?.resource) {
3751
+ this.logger.error("Failed to read resource file %s for solution %s: invalid content", undefined, resourceFile, context.path);
3752
+ return {
3753
+ file: resourceFile,
3754
+ outcome: "invalid",
3755
+ timings: failureTimings()
3756
+ };
3757
+ }
3758
+ const files = [];
3759
+ const rd = this.fromSerializable(wrapper.resource, files);
3760
+ this.applyFolders(rd, resourceFile);
3761
+ const parseMs = nowMs() - parseStarted;
3762
+ let hash;
3763
+ let hashMs = 0;
3764
+ if (computeHash) {
3765
+ const hashStarted = nowMs();
3766
+ hash = await this.computeHash(content);
3767
+ hashMs = nowMs() - hashStarted;
3768
+ }
3769
+ return {
3770
+ file: resourceFile,
3771
+ outcome: "loaded",
3772
+ resource: rd,
3773
+ files,
3774
+ normalizedPath: this.getNormalizedPath(resourceFile),
3775
+ hash,
3776
+ timings: {
3777
+ ioMs,
3778
+ parseMs,
3779
+ hashMs,
3780
+ chars: content.length
3781
+ }
3782
+ };
3783
+ } catch (ex) {
3784
+ if (ex instanceof OperationCancelledException || cancellationToken?.aborted) {
3785
+ this.logger.warn("Operation cancelled while reading file %s for solution %s", resourceFile, context.path);
3786
+ return {
3787
+ file: resourceFile,
3788
+ outcome: "fatal",
3789
+ fatal: ex instanceof OperationCancelledException ? ex : cancellationError(cancellationToken),
3790
+ timings: failureTimings()
3791
+ };
3792
+ }
3793
+ if (ex instanceof TimeoutException)
3794
+ return {
3795
+ file: resourceFile,
3796
+ outcome: "fatal",
3797
+ fatal: new TimeoutException(`Reading resource file ${resourceFile} for solution ${context.path} timed out: ${ex.message}`, ex.timeoutMs),
3798
+ timings: failureTimings()
3799
+ };
3800
+ if (isFileNotFoundError(ex)) {
3801
+ this.logger.warn("Resource file listed but missing in storage for solution %s: %s", resourceFile, context.path);
3802
+ return {
3803
+ file: resourceFile,
3804
+ outcome: "missing",
3805
+ timings: failureTimings()
3806
+ };
3807
+ }
3808
+ this.logger.error("Failed to read resource file %s for solution %s", ex, resourceFile, context.path);
3809
+ return {
3810
+ file: resourceFile,
3811
+ outcome: "parseError",
3812
+ timings: failureTimings()
3813
+ };
3587
3814
  }
3588
- return solution;
3815
+ }
3816
+ applyFolders(resource, resourceFile) {
3817
+ const relPath = resourceFile.replace(/\\/g, "/");
3818
+ const segments = relPath.split("/").filter((s) => s.length > 0);
3819
+ const firstSegment = segments[0];
3820
+ if (segments.length >= 3 && firstSegment && firstSegment.toLowerCase() === SolutionConstants.RESOURCE_FILES_FOLDER_NAME.toLowerCase()) {
3821
+ const hasType = !!resource.type;
3822
+ const folderSegmentCount = hasType ? segments.length - 3 : segments.length - 2;
3823
+ if (folderSegmentCount < 1)
3824
+ resource.folders = [
3825
+ {
3826
+ fullyQualifiedName: SolutionConstants.ROOT_FOLDER_NAME
3827
+ }
3828
+ ];
3829
+ else {
3830
+ const segmentsToUse = segments.slice(1, folderSegmentCount);
3831
+ const folderFqn = segmentsToUse.join("/");
3832
+ resource.folders = [
3833
+ {
3834
+ fullyQualifiedName: folderFqn
3835
+ }
3836
+ ];
3837
+ }
3838
+ } else
3839
+ resource.folders = [
3840
+ {
3841
+ fullyQualifiedName: SolutionConstants.ROOT_FOLDER_NAME
3842
+ }
3843
+ ];
3589
3844
  }
3590
3845
  async writeAsync(context, solution, cancellationToken) {
3591
3846
  if (context.isReadOnly)
@@ -3890,7 +4145,7 @@ class MultiFileSolutionDefinitionFactory {
3890
4145
  // ../../node_modules/@uipath/resource-builder-sdk/dist/embedded-files-default.js
3891
4146
  async function createDefaultEmbeddedFileReaderAsync() {
3892
4147
  const [{ EmbeddedFileReader }, { JsonSerializerFactory: JsonSerializerFactory2 }] = await Promise.all([
3893
- import("./embedded-file-reader-v8c2yj2a.js"),
4148
+ import("./embedded-file-reader-r66242ey.js"),
3894
4149
  import("./index-kmp9fmhb.js")
3895
4150
  ]);
3896
4151
  return new EmbeddedFileReader(new JsonSerializerFactory2);
@@ -3908,6 +4163,7 @@ var ServiceTokens = {
3908
4163
  SecretsProvider: "ISecretsProvider",
3909
4164
  FileStorageProviderFactory: "IFileStorageProviderFactory",
3910
4165
  IpRangeBypassSecretProvider: "IIpRangeBypassSecretProvider",
4166
+ FeatureFlagProvider: "IFeatureFlagProvider",
3911
4167
  SolutionDefinitionProvider: "ISolutionDefinitionProvider",
3912
4168
  SolutionDefinitionFactory: "ISolutionDefinitionFactory",
3913
4169
  ArtifactResourceSpecEnhancer: "IArtifactResourceSpecEnhancer",
@@ -4258,6 +4514,9 @@ function getBindingType(resourceKind, resourceType) {
4258
4514
  }
4259
4515
 
4260
4516
  // ../../node_modules/@uipath/resource-builder-sdk/dist/bindings/bindings-metadata-serializer.js
4517
+ var SUPPORTED_SCHEMA_MAJOR_VERSION = 2;
4518
+ var INT32_MAX_VALUE = 2147483647;
4519
+
4261
4520
  class BindingsMetadataSerializer {
4262
4521
  tryDeserialize(input) {
4263
4522
  if (!input)
@@ -4268,30 +4527,52 @@ class BindingsMetadataSerializer {
4268
4527
  let cleanInput = input.charCodeAt(0) === 65279 ? input.slice(1) : input;
4269
4528
  if (cleanInput.charCodeAt(cleanInput.length - 1) === 26)
4270
4529
  cleanInput = cleanInput.slice(0, -1);
4271
- const jsonObject = JSON.parse(cleanInput);
4530
+ const root = JSON.parse(cleanInput);
4531
+ if (root === null || typeof root != "object" || Array.isArray(root)) {
4532
+ this.logger.warn("Invalid bindings: content is not a JSON object");
4533
+ return {
4534
+ success: false
4535
+ };
4536
+ }
4537
+ const jsonObject = root;
4272
4538
  const versionValue = jsonObject[BindingsKnownKeys.Version];
4273
- if (!versionValue)
4539
+ if (typeof versionValue != "string") {
4540
+ this.logger.warn(`Invalid bindings: '${BindingsKnownKeys.Version}' is missing or not a string`);
4541
+ return {
4542
+ success: false
4543
+ };
4544
+ }
4545
+ const majorVersion = BindingsMetadataSerializer.tryParseMajorVersion(versionValue);
4546
+ if (majorVersion === undefined) {
4547
+ this.logger.warn(`Invalid bindings: '${BindingsKnownKeys.Version}' is not a valid version`);
4548
+ return {
4549
+ success: false
4550
+ };
4551
+ }
4552
+ if (majorVersion !== SUPPORTED_SCHEMA_MAJOR_VERSION) {
4553
+ this.logger.warn(`Invalid bindings: unsupported schema major version ${majorVersion}`);
4274
4554
  return {
4275
4555
  success: false
4276
4556
  };
4277
- const versionParts = versionValue.split(".").map(Number);
4278
- const majorVersion = versionParts[0];
4279
- if (majorVersion !== 2)
4280
- throw new Error("Unsupported bindings schema");
4557
+ }
4558
+ const resources = jsonObject[BindingsKnownKeys.Resources];
4559
+ if (!Array.isArray(resources)) {
4560
+ this.logger.warn(`Invalid bindings: '${BindingsKnownKeys.Resources}' is missing or not an array`);
4561
+ return {
4562
+ success: false
4563
+ };
4564
+ }
4281
4565
  const metadata = {
4282
4566
  version: versionValue,
4283
4567
  resources: []
4284
4568
  };
4285
- const resources = jsonObject[BindingsKnownKeys.Resources];
4286
- if (Array.isArray(resources))
4287
- for (const resourceElement of resources) {
4288
- if (resourceElement == null) {
4289
- this.logger.warn("Skipping null bindings resource element");
4290
- continue;
4291
- }
4292
- const resource = this.getBindingsResourceV2(resourceElement);
4293
- metadata.resources.push(resource);
4569
+ for (const resourceElement of resources) {
4570
+ if (resourceElement == null) {
4571
+ this.logger.warn("Skipping null bindings resource element");
4572
+ continue;
4294
4573
  }
4574
+ metadata.resources.push(this.getBindingsResourceV2(resourceElement));
4575
+ }
4295
4576
  this.linkDependencies(metadata.resources);
4296
4577
  return {
4297
4578
  success: true,
@@ -4304,6 +4585,22 @@ class BindingsMetadataSerializer {
4304
4585
  };
4305
4586
  }
4306
4587
  }
4588
+ static tryParseMajorVersion(value) {
4589
+ const parts = value.split(".");
4590
+ if (parts.length < 2 || parts.length > 4)
4591
+ return;
4592
+ let major;
4593
+ for (const [index, part] of parts.entries()) {
4594
+ if (!/^\s*[+-]?\d+\s*$/.test(part))
4595
+ return;
4596
+ const component = Number(part);
4597
+ if (component < 0 || component > INT32_MAX_VALUE)
4598
+ return;
4599
+ if (index === 0)
4600
+ major = component === 0 ? 0 : component;
4601
+ }
4602
+ return major;
4603
+ }
4307
4604
  linkDependencies(resources) {
4308
4605
  for (const resource of resources) {
4309
4606
  const propertyMeta = resource.metadata;
@@ -4490,8 +4787,7 @@ class BindingOverwritesHandler {
4490
4787
  [BindingsKnownKeys.FolderKeyPropertyName]: resourceOverwrite.folderKey ?? ""
4491
4788
  };
4492
4789
  else {
4493
- const isBusinessRule = bindingResource.binding.resourceType === models_BindingsResourceType.BusinessRule;
4494
- const folderPath = bindingResource.isArtefactResource && !isBusinessRule ? "" : resourceOverwrite.folderFullyQualifiedName ?? "";
4790
+ const folderPath = bindingResource.isArtefactResource && !bindingResource.isCodedApp ? "" : resourceOverwrite.folderFullyQualifiedName ?? "";
4495
4791
  overwrite = {
4496
4792
  [BindingsKnownKeys.FolderPathPropertyName]: folderPath,
4497
4793
  [BindingsKnownKeys.NamePropertyName]: resourceOverwrite.resourceName
@@ -4524,6 +4820,11 @@ function removeTimeTriggerBindings(bindings) {
4524
4820
  }
4525
4821
 
4526
4822
  // ../../node_modules/@uipath/resource-builder-sdk/dist/bindings/binding-overwrites-mapping-handler.js
4823
+ function isCodedAppType(type) {
4824
+ const normalized = type?.toLowerCase();
4825
+ return normalized === "coded" || normalized === "codedaction";
4826
+ }
4827
+
4527
4828
  class BindingOverwritesMappingRequestHandler {
4528
4829
  async handleAsync(request, cancellationToken) {
4529
4830
  const solutionBindings = request.bindings.resources.filter((x) => isSolutionResource(x.metadata));
@@ -4549,7 +4850,8 @@ class BindingOverwritesMappingRequestHandler {
4549
4850
  result.push({
4550
4851
  binding: bindingsResource,
4551
4852
  resourceKey: resource.key,
4552
- isArtefactResource: resource.projectKey != null
4853
+ isArtefactResource: resource.projectKey != null,
4854
+ isCodedApp: bindingsResource.resourceType === models_BindingsResourceType.App && isCodedAppType(resource.type)
4553
4855
  });
4554
4856
  } else {
4555
4857
  this.logger.error(`Solution does not contain binding resource of type ${models_BindingsResourceType[bindingsResource.resourceType]}.`);
@@ -5554,6 +5856,9 @@ class SolutionPublishLocationRequest {
5554
5856
  }
5555
5857
 
5556
5858
  class SolutionPublishLocationRequestV2 {
5859
+ constructor(permissionType) {
5860
+ this.permissionType = permissionType;
5861
+ }
5557
5862
  }
5558
5863
 
5559
5864
  class SettingsRequest {
@@ -5718,12 +6023,13 @@ function _ts_param3(paramIndex, decorator) {
5718
6023
  }
5719
6024
 
5720
6025
  class SolutionPublishLocationRequestV2Handler {
5721
- async handleAsync(_request, cancellationToken) {
6026
+ async handleAsync(request, cancellationToken) {
5722
6027
  try {
5723
6028
  const orchestratorClient = await this.orchestratorClientFactory.getClientAsync(cancellationToken);
5724
6029
  if (!orchestratorClient)
5725
6030
  throw new InvalidOperationException("Failed to create Orchestrator client");
5726
- return await orchestratorClient.getPublishLocationsAsync(cancellationToken);
6031
+ const { permissionType } = request;
6032
+ return permissionType == null ? await orchestratorClient.getPublishLocationsAsync(cancellationToken) : await orchestratorClient.getAccessiblePublishLocationsAsync(permissionType, cancellationToken);
5727
6033
  } catch (error) {
5728
6034
  this.logger.error("An unexpected error occurred while retrieving publish locations from Automation Solutions service.", error);
5729
6035
  throw error;
@@ -7753,7 +8059,7 @@ class GetResourceKeyForProjectRequestHandler {
7753
8059
  projectKey: request.projectKey,
7754
8060
  solution: request.context.path
7755
8061
  });
7756
- const cacheKey = `prk:${request.projectKey}`;
8062
+ const cacheKey = `prk:${request.context.path}:${request.projectKey}`;
7757
8063
  const cached = await this.cacheProvider.getAsync(cacheKey, cancellationToken);
7758
8064
  if (cached && typeof cached == "object" && "resourceKey" in cached) {
7759
8065
  this.logger.info("Cache hit for project {projectKey} resource key.", {
@@ -8581,7 +8887,11 @@ class UpdateResourceConfigurationCommandHandler {
8581
8887
  for (const prop of command.properties) {
8582
8888
  const propKey = prop.property.toLowerCase();
8583
8889
  const metadata = propertiesMetadata.get(propKey);
8584
- if (!(!metadata || isAnyReferenceProperty(metadata)) && metadata.readOnly !== true) {
8890
+ if (metadata && metadata.readOnly !== true) {
8891
+ if (isAnyReferenceProperty(metadata)) {
8892
+ updated = this.setSolutionReference(solution, resource, currentConfiguration, propertiesMetadata, metadata, prop.configuredValue) || updated;
8893
+ continue;
8894
+ }
8585
8895
  if (isSecretProperty(metadata)) {
8586
8896
  const secretValue = prop.configuredValue?.toString() || "";
8587
8897
  const existingKey = currentConfiguration[metadata.property]?.toString();
@@ -8625,6 +8935,38 @@ class UpdateResourceConfigurationCommandHandler {
8625
8935
  await command.context.saveChangesAsync(cancellationToken);
8626
8936
  return resourceConfiguration;
8627
8937
  }
8938
+ setSolutionReference(solution, resource, currentConfiguration, propertiesMetadata, metadata, configuredValue) {
8939
+ const referenceKind = metadata["referenceKind"];
8940
+ if (!isSingleReferenceProperty(metadata) || isFileReferenceProperty(metadata) || typeof referenceKind != "string" || !referenceKind)
8941
+ return false;
8942
+ const requested = asReference(configuredValue);
8943
+ const target = requested?.key ? solution.resources.find((r) => invariantEquals(r.key, requested.key) && invariantEquals(r.kind, referenceKind)) : undefined;
8944
+ if (!requested || !target || invariantEquals(target.key, resource.key))
8945
+ return false;
8946
+ const dependencies = resource.dependencies ??= [];
8947
+ const previous = asReference(currentConfiguration[metadata.property]);
8948
+ const previousKey = previous?.key;
8949
+ const isReferencedElsewhere = (key) => [
8950
+ ...propertiesMetadata.values()
8951
+ ].some((p) => isAnyReferenceProperty(p) && !isFileReferenceProperty(p) && typeof p["referenceKind"] == "string" && invariantEquals(p["referenceKind"], target.kind) && !invariantEquals(p.property, metadata.property) && asReferences(currentConfiguration[p.property]).some((r) => r.key !== undefined && invariantEquals(r.key, key)));
8952
+ if (previousKey && !invariantEquals(previousKey, target.key) && !isReferencedElsewhere(previousKey)) {
8953
+ const previousName = solution.resources.find((r) => invariantEquals(r.key, previousKey) && invariantEquals(r.kind, target.kind))?.name ?? previous?.name ?? "";
8954
+ resource.dependencies = dependencies.filter((d) => !(invariantEquals(d.kind, target.kind) && invariantEquals(d.name, previousName)));
8955
+ }
8956
+ if (!resource.dependencies.some((d) => invariantEquals(d.kind, target.kind) && invariantEquals(d.name, target.name)))
8957
+ resource.dependencies.push({
8958
+ kind: target.kind,
8959
+ name: target.name
8960
+ });
8961
+ currentConfiguration[metadata.property] = {
8962
+ name: target.name,
8963
+ key: target.key,
8964
+ folderKey: requested.folderKey ?? null,
8965
+ lookupStrategy: null,
8966
+ info: null
8967
+ };
8968
+ return true;
8969
+ }
8628
8970
  async updateReferencesName(solutionDefinition, resource, oldName, cancellationToken) {
8629
8971
  const resourcesToBeChanged = solutionDefinition.resources.filter((r) => r.key !== resource.key && (r.dependencies ?? []).some((d) => invariantEquals(d.kind, resource.kind) && invariantEquals(d.name, oldName)));
8630
8972
  if (resourcesToBeChanged.length === 0)
@@ -8911,6 +9253,28 @@ class UpsertResourceSecretCommandHandler {
8911
9253
  this.secretsProvider = secretsProvider;
8912
9254
  }
8913
9255
  }
9256
+ function asReference(value) {
9257
+ if (!value || typeof value != "object" || Array.isArray(value))
9258
+ return;
9259
+ const record = value;
9260
+ const pick = (name) => {
9261
+ const entry = Object.entries(record).find(([k]) => k.toLowerCase() === name.toLowerCase());
9262
+ return typeof entry?.[1] == "string" ? entry[1] : undefined;
9263
+ };
9264
+ return {
9265
+ key: pick("key"),
9266
+ name: pick("name"),
9267
+ folderKey: pick("folderKey")
9268
+ };
9269
+ }
9270
+ function asReferences(value) {
9271
+ if (Array.isArray(value))
9272
+ return value.map(asReference).filter((r) => r !== undefined);
9273
+ const single = asReference(value);
9274
+ return single ? [
9275
+ single
9276
+ ] : [];
9277
+ }
8914
9278
 
8915
9279
  // ../../node_modules/@uipath/resource-builder-sdk/dist/handlers/solution-handlers.js
8916
9280
  var DUPLICATE_NAMES_SUPPORTED_KINDS = new Set([
@@ -9882,6 +10246,9 @@ class ResourceCatalogApi extends HttpClient {
9882
10246
  // ../../node_modules/@uipath/resource-builder-sdk/dist/clients/resource-catalog/resource-catalog-client.factory.js
9883
10247
  var RESOURCE_CATALOG_SCOPE = "RCS.FolderAuthorization";
9884
10248
  var RESOURCE_CATALOG_SERVICE_NAME = "resourcecatalog";
10249
+ function trimTrailingSlashes(url) {
10250
+ return url.replace(/\/+$/, "");
10251
+ }
9885
10252
 
9886
10253
  class ResourceCatalogClientFactory {
9887
10254
  async getClientAsync(cancellationToken) {
@@ -9895,9 +10262,8 @@ class ResourceCatalogClientFactory {
9895
10262
  ], true, cancellationToken);
9896
10263
  const ipRangeBypassSecret = await this.ipRangeBypassSecretProvider?.getIpRangeBypassSecretAsync(cancellationToken);
9897
10264
  const gatewayIntegrationEnabled = this.resourceBuilderAccessProvider.isGatewayIntegrationEnabled();
9898
- const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
9899
10265
  const client = new ResourceCatalogApi({
9900
- baseUrl: normalizedBaseUrl,
10266
+ baseUrl: trimTrailingSlashes(baseUrl),
9901
10267
  securityWorker: (securityData) => {
9902
10268
  if (!securityData)
9903
10269
  return {};
@@ -9940,7 +10306,7 @@ class ResourceCatalogClientFactory {
9940
10306
  if (!accountKey)
9941
10307
  throw new Error("Unable to obtain account key");
9942
10308
  const client = new ResourceCatalogApi({
9943
- baseUrl,
10309
+ baseUrl: trimTrailingSlashes(baseUrl),
9944
10310
  securityWorker: (securityData) => {
9945
10311
  if (!securityData)
9946
10312
  return {};
@@ -12159,7 +12525,16 @@ class AutomationSolutionsClientProxy2 {
12159
12525
  // ../../node_modules/@uipath/resource-builder-sdk/dist/clients/orchestrator/orchestrator-client.js
12160
12526
  class OrchestratorClient {
12161
12527
  async getPublishLocationsAsync(cancellationToken) {
12162
- const url = `${this.options.baseUrl}api/v2/AutomationSolutions/publish_locations`;
12528
+ return this.getPublishLocationsFromAsync(this.publishLocationsUrl(), cancellationToken);
12529
+ }
12530
+ async getAccessiblePublishLocationsAsync(permissionType, cancellationToken) {
12531
+ const url = `${this.publishLocationsUrl()}?permissionType=${encodeURIComponent(permissionType)}`;
12532
+ return this.getPublishLocationsFromAsync(url, cancellationToken);
12533
+ }
12534
+ publishLocationsUrl() {
12535
+ return `${this.options.baseUrl}api/v2/AutomationSolutions/publish_locations`;
12536
+ }
12537
+ async getPublishLocationsFromAsync(url, cancellationToken) {
12163
12538
  const headers = OrchestratorClientFactory.buildHeaders(this.options.securityData);
12164
12539
  const response = await fetch(url, {
12165
12540
  method: "GET",
@@ -12849,7 +13224,7 @@ class ReconcileProjectsCommandHandler {
12849
13224
  } : {
12850
13225
  resourceKey: undefined
12851
13226
  };
12852
- await this.cacheProvider.setAsync(`prk:${projectKey}`, result, cancellationToken);
13227
+ await this.cacheProvider.setAsync(`prk:${context.path}:${projectKey}`, result, cancellationToken);
12853
13228
  }
12854
13229
  groupByProjectKey(artefactResources) {
12855
13230
  const map = new Map;
@@ -13723,6 +14098,11 @@ class ResourceBuilder {
13723
14098
  const request = new SolutionPublishLocationRequestV2;
13724
14099
  return this._mediator.sendAsync(request, cancellationToken);
13725
14100
  }
14101
+ async getAccessiblePublishLocationsAsync(permissionType, cancellationToken) {
14102
+ this.throwIfCancelled(cancellationToken);
14103
+ const request = new SolutionPublishLocationRequestV2(permissionType);
14104
+ return this._mediator.sendAsync(request, cancellationToken);
14105
+ }
13726
14106
  async getSettingsAsync(cancellationToken) {
13727
14107
  this.throwIfCancelled(cancellationToken);
13728
14108
  const request = new SettingsRequest;
@@ -14282,9 +14662,9 @@ class UnconfiguredEmbeddedFileReader {
14282
14662
  }
14283
14663
 
14284
14664
  // ../../node_modules/@uipath/resource-builder-sdk/dist/container.js
14285
- function createContainer(accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, httpReaderOptions, loggerFactory, embeddedFileReader, solutionContextOptions) {
14665
+ function createContainer(accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, httpReaderOptions, loggerFactory, embeddedFileReader, solutionContextOptions, featureFlagProvider) {
14286
14666
  const childContainer = import_tsyringe6.container.createChildContainer();
14287
- registerProviders(childContainer, accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, httpReaderOptions, loggerFactory, solutionContextOptions);
14667
+ registerProviders(childContainer, accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, httpReaderOptions, loggerFactory, solutionContextOptions, featureFlagProvider);
14288
14668
  registerServices(childContainer, embeddedFileReader);
14289
14669
  registerHandlers(childContainer);
14290
14670
  childContainer.register(ServiceTokens.Mediator, {
@@ -14308,11 +14688,15 @@ function registerProvider(diContainer, token, provider) {
14308
14688
  break;
14309
14689
  }
14310
14690
  }
14311
- function registerProviders(diContainer, accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, httpReaderOptions, loggerFactory, solutionContextOptions) {
14691
+ function registerProviders(diContainer, accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, httpReaderOptions, loggerFactory, solutionContextOptions, featureFlagProvider) {
14312
14692
  registerProvider(diContainer, ServiceTokens.AccessProvider, accessProvider);
14313
14693
  registerProvider(diContainer, ServiceTokens.CacheProvider, cacheProvider);
14314
14694
  registerProvider(diContainer, ServiceTokens.SecretsProvider, secretsProvider);
14315
14695
  registerProvider(diContainer, ServiceTokens.IpRangeBypassSecretProvider, ipRangeBypassSecretProvider);
14696
+ registerProvider(diContainer, ServiceTokens.FeatureFlagProvider, featureFlagProvider ?? {
14697
+ instance: new NullFeatureFlagProvider,
14698
+ lifetime: service_tokens_ServiceLifetime.Singleton
14699
+ });
14316
14700
  registerProvider(diContainer, ServiceTokens.FileStorageProviderFactory, fileStorageProviderFactory);
14317
14701
  registerProvider(diContainer, ServiceTokens.SolutionDefinitionProvider, solutionDefinitionProvider);
14318
14702
  registerProvider(diContainer, ServiceTokens.SolutionDefinitionFactory, solutionDefinitionFactory);
@@ -15039,6 +15423,11 @@ class ResourceBuilderConfiguration {
15039
15423
  this._ipRangeBypassSecretProviderLifetime = lifetime;
15040
15424
  return this;
15041
15425
  }
15426
+ addFeatureFlagProvider(provider, lifetime = service_tokens_ServiceLifetime.Scoped) {
15427
+ this._featureFlagProviderProvider = provider;
15428
+ this._featureFlagProviderLifetime = lifetime;
15429
+ return this;
15430
+ }
15042
15431
  addSolutionDefinitionProvider(provider, lifetime = service_tokens_ServiceLifetime.Scoped) {
15043
15432
  this._solutionDefinitionProviderProvider = provider;
15044
15433
  this._solutionDefinitionProviderLifetime = lifetime;
@@ -15092,6 +15481,11 @@ class ResourceBuilderConfiguration {
15092
15481
  instance: ipRangeBypassSecretProviderInstance,
15093
15482
  lifetime: this._ipRangeBypassSecretProviderLifetime
15094
15483
  };
15484
+ const featureFlagProviderInstance = this._featureFlagProviderProvider ? await resolveProvider(this._featureFlagProviderProvider) : new NullFeatureFlagProvider;
15485
+ const featureFlagProvider = {
15486
+ instance: featureFlagProviderInstance,
15487
+ lifetime: this._featureFlagProviderLifetime
15488
+ };
15095
15489
  const secretsProviderInstance = this._secretsProviderProvider ? await resolveProvider(this._secretsProviderProvider) : new NullSecretsProvider;
15096
15490
  const secretsProvider = {
15097
15491
  instance: secretsProviderInstance,
@@ -15135,7 +15529,7 @@ class ResourceBuilderConfiguration {
15135
15529
  lifetime: this._artifactResourceSpecEnhancerLifetime
15136
15530
  };
15137
15531
  const embeddedFileReader = await createDefaultEmbeddedFileReaderAsync();
15138
- const container3 = createContainer(accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, this._httpReaderOptions, loggerFactory, embeddedFileReader, this._solutionContextOptions);
15532
+ const container3 = createContainer(accessProvider, cacheProvider, secretsProvider, fileStorageProviderFactory, ipRangeBypassSecretProvider, solutionDefinitionProvider, solutionDefinitionFactory, artifactResourceSpecEnhancer, this._httpReaderOptions, loggerFactory, embeddedFileReader, this._solutionContextOptions, featureFlagProvider);
15139
15533
  return new ResourceBuilderServices(container3);
15140
15534
  }
15141
15535
  async buildServices() {
@@ -15147,6 +15541,7 @@ class ResourceBuilderConfiguration {
15147
15541
  this._secretsProviderLifetime = service_tokens_ServiceLifetime.Scoped;
15148
15542
  this._fileStorageProviderFactoryLifetime = service_tokens_ServiceLifetime.Singleton;
15149
15543
  this._ipRangeBypassSecretProviderLifetime = service_tokens_ServiceLifetime.Scoped;
15544
+ this._featureFlagProviderLifetime = service_tokens_ServiceLifetime.Scoped;
15150
15545
  this._solutionDefinitionProviderLifetime = service_tokens_ServiceLifetime.Scoped;
15151
15546
  this._solutionDefinitionFactoryLifetime = service_tokens_ServiceLifetime.Scoped;
15152
15547
  this._artifactResourceSpecEnhancerLifetime = service_tokens_ServiceLifetime.Scoped;
@@ -15258,8 +15653,59 @@ var ARTEFACT_KIND_APP = "app";
15258
15653
  var ARTEFACT_KIND_APP_VERSION = "appversion";
15259
15654
  var ARTEFACT_KIND_PACKAGE = "package";
15260
15655
  var SPEC_KEY_PACKAGE = "package";
15656
+ var RESOURCE_FILES_FOLDER_NAME = "resources";
15657
+ var RESOURCE_FILE_PATTERN = "*.json";
15658
+ var FIX_SHARED_KEY = "Delete all but one file for each key, then retry.";
15659
+ var FIX_KEYLESS = 'Give each file without a key its own unique "key", then retry.';
15660
+
15661
+ class DuplicateKeysError extends Error {
15662
+ keys;
15663
+ constructor(keys) {
15664
+ super(`Duplicate resource keys: ${keys.map(describeKey).join(", ")}`);
15665
+ this.keys = keys;
15666
+ }
15667
+ }
15261
15668
 
15262
15669
  class ArtefactPairBindingProvider extends MultiFileSolutionDefinitionProvider {
15670
+ async readAsync(context, cancellationToken) {
15671
+ const [readError, solution] = await catchError(super.readAsync(context, cancellationToken));
15672
+ if (!readError)
15673
+ return solution;
15674
+ if (!(readError instanceof DuplicateKeysError))
15675
+ throw readError;
15676
+ const [describeError, message] = await catchError(this.describeDuplicateKeys(context, readError.keys, cancellationToken));
15677
+ throw describeError ? readError : new Error(message);
15678
+ }
15679
+ async replaceDuplicateKeysAsync(solution) {
15680
+ const keys = findDuplicateKeys(solution);
15681
+ if (keys.length > 0)
15682
+ throw new DuplicateKeysError(keys);
15683
+ }
15684
+ async describeDuplicateKeys(context, keys, cancellationToken) {
15685
+ const storage = await this.getFileStorageProviderAsync(context, cancellationToken);
15686
+ const files = await storage.getFilesAsync(RESOURCE_FILES_FOLDER_NAME, RESOURCE_FILE_PATTERN, cancellationToken);
15687
+ const pathsByKey = new Map(keys.map((key) => [key, []]));
15688
+ for (const file of [...files].sort()) {
15689
+ const [readError, key] = await catchError(this.readResourceKey(storage, file, cancellationToken));
15690
+ if (readError)
15691
+ continue;
15692
+ pathsByKey.get(key)?.push(toPortableRelativePath(file));
15693
+ }
15694
+ const lines = [...pathsByKey].map(([key, paths]) => `Resource key ${describeKey(key)} is used by: ${paths.join(", ")}`);
15695
+ const fixes = [
15696
+ keys.some((key) => !isKeyless(key)) && FIX_SHARED_KEY,
15697
+ keys.some(isKeyless) && FIX_KEYLESS
15698
+ ].filter(Boolean);
15699
+ return [...lines, ...fixes].join(`
15700
+ `);
15701
+ }
15702
+ async readResourceKey(storage, file, cancellationToken) {
15703
+ const content = await storage.readFileToEndAsync(file, cancellationToken);
15704
+ const wrapper = this.caseInsensitiveSerializer.deserialize(content);
15705
+ if (!wrapper?.resource)
15706
+ throw new Error(`No resource in ${file}`);
15707
+ return wrapper.resource.key;
15708
+ }
15263
15709
  async writeAsync(context, solution, cancellationToken) {
15264
15710
  patchAppPackageLinkage(solution);
15265
15711
  return super.writeAsync(context, solution, cancellationToken);
@@ -15271,6 +15717,22 @@ class ArtefactPairBindingSolutionDefinitionFactory extends MultiFileSolutionDefi
15271
15717
  return new ArtefactPairBindingProvider(this.fileStorageProviderFactory, this.jsonSerializerFactory, this.loggerFactory);
15272
15718
  }
15273
15719
  }
15720
+ function findDuplicateKeys(solution) {
15721
+ const counts = new Map;
15722
+ for (const resource of solution.resources ?? []) {
15723
+ const key = resource.key;
15724
+ counts.set(key, (counts.get(key) ?? 0) + 1);
15725
+ }
15726
+ return [...counts].filter(([, count]) => count > 1).map(([key]) => key);
15727
+ }
15728
+ function isKeyless(key) {
15729
+ return typeof key !== "string" || !key;
15730
+ }
15731
+ function describeKey(key) {
15732
+ if (typeof key === "string" && key)
15733
+ return key;
15734
+ return key === undefined ? "(missing)" : JSON.stringify(key);
15735
+ }
15274
15736
  function patchAppPackageLinkage(solution) {
15275
15737
  const resources = solution.resources ?? [];
15276
15738
  const projectKeys = new Set;
@@ -15742,6 +16204,108 @@ async function createProjectInSolutionBuilder(solutionDir, projectId, projectNam
15742
16204
  await catchError(solutionBuilder.disposeAsync());
15743
16205
  return createError;
15744
16206
  }
16207
+ // ../solution-sdk/src/resources/services/catalog-lookup-failure.ts
16208
+ var NO_CLIENT_MESSAGE = "Unable to create Resource Catalog client";
16209
+ function classifyCatalogFailure(error) {
16210
+ const message = error instanceof Error ? error.message : String(error);
16211
+ if (message.includes(NO_CLIENT_MESSAGE)) {
16212
+ return { message, kind: "no_session" };
16213
+ }
16214
+ const match = /\bHTTP (\d{3})\b/.exec(message);
16215
+ const status = match ? Number(match[1]) : undefined;
16216
+ if (status === 401 || status === 403) {
16217
+ return { message, kind: "refused", status };
16218
+ }
16219
+ return { message, kind: "failed", ...status ? { status } : {} };
16220
+ }
16221
+ function stopsCatalogLookups(failure) {
16222
+ return failure.kind !== "failed";
16223
+ }
16224
+ function describeBindings(bindings) {
16225
+ return bindings.map((b) => `${b.kind} "${b.name}"`).join(", ");
16226
+ }
16227
+ function describeCause(failure) {
16228
+ switch (failure.kind) {
16229
+ case "no_session":
16230
+ return "There is no login, so the Resource Catalog could not be searched";
16231
+ case "refused":
16232
+ return `The Resource Catalog refused this login (${failure.message})`;
16233
+ default:
16234
+ return `A Resource Catalog call failed (${failure.message})`;
16235
+ }
16236
+ }
16237
+ function classify(failure) {
16238
+ const refreshAndCommit = "or run 'uip solution resources refresh' under a login the Resource Catalog accepts and commit the solution's resources. The resources already in the solution are used as they are.";
16239
+ if (failure.kind === "no_session") {
16240
+ return {
16241
+ errorCode: "authentication_required",
16242
+ retry: "RetryWillNotFix",
16243
+ instructions: `Run 'uip login', then re-run; ${refreshAndCommit}`
16244
+ };
16245
+ }
16246
+ if (failure.kind === "refused") {
16247
+ return {
16248
+ errorCode: "permission_denied",
16249
+ retry: "RetryWillNotFix",
16250
+ instructions: `Use a login the Resource Catalog accepts (a user login: 'uip login'), ${refreshAndCommit}`
16251
+ };
16252
+ }
16253
+ const status = failure.status;
16254
+ if (status === 429) {
16255
+ return {
16256
+ errorCode: "rate_limited",
16257
+ retry: "RetryLater",
16258
+ instructions: `Wait, then re-run; ${refreshAndCommit}`
16259
+ };
16260
+ }
16261
+ if (status !== undefined && status >= 500) {
16262
+ return {
16263
+ errorCode: "server_error",
16264
+ retry: "RetryLater",
16265
+ instructions: `Retry once the Resource Catalog is back; ${refreshAndCommit}`
16266
+ };
16267
+ }
16268
+ if (status !== undefined && status >= 400) {
16269
+ return {
16270
+ errorCode: "unknown_error",
16271
+ retry: "RetryWillNotFix",
16272
+ instructions: `The Resource Catalog rejected the lookup for these bindings, so a retry gets the same answer. Check them in the project's bindings, ${refreshAndCommit}`
16273
+ };
16274
+ }
16275
+ return {
16276
+ errorCode: "unknown_error",
16277
+ retry: "RetryLater",
16278
+ instructions: `Retry; if it keeps failing, ${refreshAndCommit}`
16279
+ };
16280
+ }
16281
+ function catalogLookupWarning(failure, kept, unresolved) {
16282
+ const parts = [
16283
+ `${describeCause(failure)}, so ${kept + unresolved.length} binding(s) were not checked against the cloud.`
16284
+ ];
16285
+ if (kept > 0) {
16286
+ parts.push(`${kept} already in the solution were kept as they are.`);
16287
+ }
16288
+ if (unresolved.length > 0) {
16289
+ parts.push(`Not added to the solution: ${describeBindings(unresolved)}.`);
16290
+ }
16291
+ return parts.join(" ");
16292
+ }
16293
+
16294
+ class CatalogLookupError extends Error {
16295
+ errorCode;
16296
+ retry;
16297
+ instructions;
16298
+ unresolved;
16299
+ constructor(failure, unresolved) {
16300
+ super(`${describeCause(failure)}, so these bindings could not be resolved and are not in the solution: ${describeBindings(unresolved)}.`);
16301
+ this.name = "CatalogLookupError";
16302
+ const { errorCode, retry, instructions } = classify(failure);
16303
+ this.errorCode = errorCode;
16304
+ this.retry = retry;
16305
+ this.instructions = instructions;
16306
+ this.unresolved = unresolved;
16307
+ }
16308
+ }
15745
16309
  // ../solution-sdk/src/resources/services/local-resource-matcher.ts
15746
16310
  function normalizeFolderPath(path) {
15747
16311
  if (!path)
@@ -15847,6 +16411,20 @@ async function findCatalogEntityAsync(catalog, query, match) {
15847
16411
  } while (pageCursor);
15848
16412
  return;
15849
16413
  }
16414
+ async function findCatalogEntitiesAsync(catalog, query, match) {
16415
+ const found = [];
16416
+ let pageCursor;
16417
+ do {
16418
+ const page = await catalog.searchFolderEntities({
16419
+ ...query,
16420
+ pageSize: 100,
16421
+ pageCursor
16422
+ });
16423
+ found.push(...(page.items ?? []).filter(match));
16424
+ pageCursor = page.nextPage ?? undefined;
16425
+ } while (pageCursor);
16426
+ return found;
16427
+ }
15850
16428
  function toResourceReference(entity) {
15851
16429
  return toCatalogReference({
15852
16430
  kind: entity.entityType ?? "",
@@ -15900,7 +16478,7 @@ function parseJsonString(raw) {
15900
16478
  return error ? undefined : parsed;
15901
16479
  }
15902
16480
  // ../solution-sdk/src/resources/services/resource-casing.ts
15903
- var RESOURCE_FILES_FOLDER_NAME = "resources";
16481
+ var RESOURCE_FILES_FOLDER_NAME2 = "resources";
15904
16482
  function lowerFirstChar(value) {
15905
16483
  return value ? value.charAt(0).toLowerCase() + value.slice(1) : value;
15906
16484
  }
@@ -15929,7 +16507,7 @@ async function saveCasingNormalized(builder) {
15929
16507
  }
15930
16508
  async function normalizeResourceFileCasing(solutionDir) {
15931
16509
  const fs = getFileSystem();
15932
- const root = fs.path.join(solutionDir, RESOURCE_FILES_FOLDER_NAME);
16510
+ const root = fs.path.join(solutionDir, RESOURCE_FILES_FOLDER_NAME2);
15933
16511
  if (!await fs.exists(root))
15934
16512
  return [];
15935
16513
  const byTarget = new Map;
@@ -15977,13 +16555,17 @@ function targetSegments(segments, kind, type) {
15977
16555
  const kindIndex = type ? target.length - 3 : target.length - 2;
15978
16556
  if (kindIndex < 0)
15979
16557
  return target;
15980
- if (target[kindIndex] === kind)
16558
+ if (sameIgnoringCase(target[kindIndex], kind)) {
15981
16559
  target[kindIndex] = lowerFirstChar(kind);
15982
- if (type && target[kindIndex + 1] === type) {
16560
+ }
16561
+ if (type && sameIgnoringCase(target[kindIndex + 1], type)) {
15983
16562
  target[kindIndex + 1] = lowerFirstChar(type);
15984
16563
  }
15985
16564
  return target;
15986
16565
  }
16566
+ function sameIgnoringCase(a, b) {
16567
+ return a.toLowerCase() === b.toLowerCase();
16568
+ }
15987
16569
  async function collectResourceFiles(root, segments) {
15988
16570
  const fs = getFileSystem();
15989
16571
  const [readError, names] = await catchError(fs.readdir(fs.path.join(root, ...segments)));
@@ -16056,6 +16638,118 @@ function parseResourceHeader(content) {
16056
16638
  return null;
16057
16639
  }
16058
16640
  }
16641
+ // ../solution-sdk/src/resources/services/resource-configurations.ts
16642
+ var ROOT_RESOURCE_TYPES = new Set(["resource", "solutionresource"]);
16643
+ var KEY_NOT_FOUND = /^(?:Solution)?Resource with key '([^']+)' was not found$/i;
16644
+ function isResourceKeyNotFound(error, resourceKey) {
16645
+ if (!(error instanceof Error))
16646
+ return false;
16647
+ const typed = error;
16648
+ const sameKey = (key) => key !== undefined && key.toLowerCase() === resourceKey.toLowerCase();
16649
+ if (typeof typed.resourceType === "string" && typeof typed.resourceKey === "string") {
16650
+ return ROOT_RESOURCE_TYPES.has(typed.resourceType.toLowerCase()) && sameKey(typed.resourceKey);
16651
+ }
16652
+ return sameKey(KEY_NOT_FOUND.exec(error.message.trim())?.[1]);
16653
+ }
16654
+ async function refreshArtefactSpecsAsync(builder, configurations) {
16655
+ const resources = new Map;
16656
+ const [loadError, solution] = await catchError(builder.context.loadAsync());
16657
+ if (loadError || !solution)
16658
+ return resources;
16659
+ for (const configuration of configurations) {
16660
+ const resource = solution.resources.find((r) => r.key === configuration?.key);
16661
+ if (!resource)
16662
+ continue;
16663
+ resources.set(resource.key, resource);
16664
+ if (!resource.projectKey)
16665
+ continue;
16666
+ configuration.spec = await applyEntryPointEnhancementAsync(builder.context, resource, configuration.spec ?? {});
16667
+ }
16668
+ return resources;
16669
+ }
16670
+ async function exportResourceConfigurationsAsync(services, resourceKey, hint = {}) {
16671
+ const { catalog, importer } = getRemoteResourceClients(services);
16672
+ const byKey = (item) => item.entityKey === resourceKey;
16673
+ const entity = (hint.name ? await findCatalogEntityAsync(catalog, { name: hint.name }, byKey) : undefined) ?? await findCatalogEntityAsync(catalog, {}, byKey);
16674
+ if (!entity) {
16675
+ throw new Error(`Resource '${resourceKey}' was not found in the solution or in the resource catalog`);
16676
+ }
16677
+ const payload = await importer.exportResourceAsync(toResourceReference(entity));
16678
+ const definitions = payload.resourceDefinitions ?? [];
16679
+ if (definitions.length === 0) {
16680
+ throw new Error(`FPS export for '${resourceKey}' returned no resource definitions`);
16681
+ }
16682
+ return {
16683
+ resources: definitions.map((d) => ({
16684
+ key: d.key ?? "",
16685
+ spec: d.spec ?? {},
16686
+ locks: d.locks ?? [],
16687
+ apiVersion: d.apiVersion,
16688
+ isOverridable: d.isOverridable,
16689
+ name: d.name ?? "",
16690
+ kind: d.kind ?? "",
16691
+ dependencies: (d.dependencies ?? []).map((dep) => ({
16692
+ kind: dep.kind ?? "",
16693
+ name: dep.name ?? ""
16694
+ }))
16695
+ }))
16696
+ };
16697
+ }
16698
+ async function readLocalAsync(builder, resourceKey, read) {
16699
+ if (!builder)
16700
+ return;
16701
+ const [error, value] = await catchError(read(builder));
16702
+ if (!error)
16703
+ return { builder, value };
16704
+ if (isResourceKeyNotFound(error, resourceKey))
16705
+ return;
16706
+ throw error;
16707
+ }
16708
+ async function readResourceConfigurationsAsync(services, builder, resourceKey, hint = {}) {
16709
+ const local = await readLocalAsync(builder, resourceKey, (b) => b.getAllConfigurationsAsync(resourceKey));
16710
+ if (!local) {
16711
+ return exportResourceConfigurationsAsync(services, resourceKey, hint);
16712
+ }
16713
+ await refreshArtefactSpecsAsync(local.builder, local.value?.resources ?? []);
16714
+ return local.value;
16715
+ }
16716
+ async function readResourceConfigurationAsync(services, builder, resourceKey) {
16717
+ const local = await readLocalAsync(builder, resourceKey, (b) => b.getConfigurationAsync(resourceKey));
16718
+ if (local) {
16719
+ const configuration = local.value;
16720
+ const resources2 = await refreshArtefactSpecsAsync(local.builder, [
16721
+ configuration
16722
+ ]);
16723
+ return { configuration, resource: resources2.get(configuration.key) };
16724
+ }
16725
+ const { resources } = await exportResourceConfigurationsAsync(services, resourceKey);
16726
+ const primary = resources.find((r) => r.key === resourceKey) ?? resources[0];
16727
+ const { key, spec, locks, apiVersion, isOverridable } = primary;
16728
+ return { configuration: { key, spec, locks, apiVersion, isOverridable } };
16729
+ }
16730
+ // ../solution-sdk/src/resources/services/resource-lookup.ts
16731
+ async function findResourcesByNameAsync(services, builder, { kind, name, subTypes, folderKey }) {
16732
+ const same = (a, b) => (a ?? "").toLowerCase() === b.toLowerCase();
16733
+ const ofSubType = (type) => subTypes === undefined || subTypes.some((t) => same(type, t));
16734
+ if (builder) {
16735
+ const solution = await builder.context.loadAsync();
16736
+ const local = solution.resources.filter((r) => same(r.kind, kind) && same(r.name, name) && ofSubType(r.type)).map((r) => ({
16737
+ key: r.key,
16738
+ local: true,
16739
+ folderPath: r.folders?.[0]?.fullyQualifiedName
16740
+ }));
16741
+ if (local.length > 0)
16742
+ return local;
16743
+ }
16744
+ const { catalog } = getRemoteResourceClients(services);
16745
+ const rows = await findCatalogEntitiesAsync(catalog, { name, entityTypes: [kind] }, (row) => same(row.entityType, kind) && same(row.entityName, name) && ofSubType(row.entitySubType) && (folderKey === undefined || same(row.folderKey, folderKey)));
16746
+ return rows.map((row) => ({
16747
+ key: row.entityKey ?? "",
16748
+ local: false,
16749
+ folderPath: row.fullyQualifiedName ?? undefined,
16750
+ folderKey: row.folderKey ?? undefined
16751
+ }));
16752
+ }
16059
16753
  // ../solution-sdk/src/resources/services/resource-name.ts
16060
16754
  var MAX_RESOURCE_NAME_LENGTH = 256;
16061
16755
  var UNSAFE_NAME_CHARS = /[\\/:*?"<>|]/;
@@ -16103,6 +16797,9 @@ var TYPE_IS_IDENTITY_REPLACE_OPTIONS = new Set([
16103
16797
  "SameNameAndType"
16104
16798
  ]);
16105
16799
  var BINDINGS_JSON_FALLBACK_TYPES = new Set(["agent", "function"]);
16800
+
16801
+ class OverwriteRefreshError extends Error {
16802
+ }
16106
16803
  function placeholderForType(type) {
16107
16804
  switch ((type ?? "string").toLowerCase()) {
16108
16805
  case "boolean":
@@ -16203,13 +16900,15 @@ function resolveBindingResourceIdentity(binding) {
16203
16900
  };
16204
16901
  }
16205
16902
  }
16206
- async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTypes) {
16903
+ async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTypes, projectBindings) {
16207
16904
  const result = {
16208
16905
  created: 0,
16209
16906
  imported: 0,
16210
16907
  skipped: 0,
16211
16908
  pruned: 0,
16212
- warnings: []
16909
+ projectResourcesCreated: 0,
16910
+ warnings: [],
16911
+ unresolved: []
16213
16912
  };
16214
16913
  const uipxProjects = await readUipxProjects(solutionDir);
16215
16914
  const paths = projectPaths ?? uipxProjects.map((p) => p.path);
@@ -16223,7 +16922,7 @@ async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTy
16223
16922
  return result;
16224
16923
  }
16225
16924
  const serializer = services.container.resolve(Tokens.IBindingsMetadataSerializer);
16226
- const { bindings: allBindings, parseErrors } = await collectBindings(solutionDir, paths, bindingsJsonFallbackDirs, serializer);
16925
+ const { bindings: allBindings, parseErrors } = await collectBindings(bindingsJsonFallbackDirs, serializer, bindingSources(solutionDir, paths, uipxProjects, projectBindings));
16227
16926
  if (parseErrors.length > 0) {
16228
16927
  const detail = parseErrors.map((e) => `${e.path}: ${e.reason}`).join("; ");
16229
16928
  throw new Error(`Invalid bindings file — ${detail}`);
@@ -16237,7 +16936,8 @@ async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTy
16237
16936
  logger.warn(`Failed to get solution builder: ${builderError.message}`);
16238
16937
  return result;
16239
16938
  }
16240
- await reconcileSolutionProjects(builder, solutionDir, projectSubTypes);
16939
+ const reconcileOutcome = await reconcileSolutionProjects(builder, solutionDir, projectSubTypes);
16940
+ result.projectResourcesCreated = reconcileOutcome.resourcesAdded;
16241
16941
  const memberProjectKeys = new Set(uipxProjects.map((project) => project.id.toLowerCase()));
16242
16942
  await pruneMemberClones(builder, memberProjectKeys, result);
16243
16943
  if (allBindings.length === 0) {
@@ -16252,6 +16952,28 @@ async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTy
16252
16952
  const resolveKindMetadata = await buildKindResolver(metadataReader);
16253
16953
  const solution = await builder.context.loadAsync();
16254
16954
  const knownResourceKeys = new Set((solution.resources ?? []).map((r) => r.key?.toLowerCase()).filter((k) => !!k));
16955
+ let keptUnchecked = 0;
16956
+ const resolvedKeys = new Set;
16957
+ const overwrittenKeys = new Set;
16958
+ const bindingKey = (kind, name) => `${kind}:${name ?? ""}`.toLowerCase();
16959
+ const recordUnchecked = async (error, kind, name, directCloudKey) => {
16960
+ if (error) {
16961
+ const failure = classifyCatalogFailure(error);
16962
+ if (!result.catalogLookupFailure || stopsCatalogLookups(failure) && !stopsCatalogLookups(result.catalogLookupFailure)) {
16963
+ result.catalogLookupFailure = failure;
16964
+ }
16965
+ }
16966
+ const covered = await isUncheckedBindingCovered(builder, knownResourceKeys, kind, name, directCloudKey);
16967
+ if (covered) {
16968
+ keptUnchecked++;
16969
+ result.skipped++;
16970
+ return;
16971
+ }
16972
+ result.unresolved.push({
16973
+ kind,
16974
+ name: directCloudKey ?? name
16975
+ });
16976
+ };
16255
16977
  const virtualCandidates = [];
16256
16978
  for (const binding of allBindings) {
16257
16979
  const identity = resolveBindingResourceIdentity(binding);
@@ -16281,7 +17003,12 @@ async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTy
16281
17003
  logger.info(`Skipping ${kind} "${name}" — the solution provisions this project itself; its member declaration covers the binding`);
16282
17004
  continue;
16283
17005
  }
16284
- const rcsMatch = directCloudKey ? await findResourceByKeyInRcs(builder, kind, directCloudKey, folderPath) : await findResourceInRcs(builder, kind, name, folderPath);
17006
+ const lookupsStopped = !!result.catalogLookupFailure && stopsCatalogLookups(result.catalogLookupFailure);
17007
+ const [lookupError, rcsMatch] = lookupsStopped ? [undefined, undefined] : await catchError(directCloudKey ? findResourceByKeyInRcs(builder, kind, directCloudKey, folderPath, true) : findResourceInRcs(builder, kind, name, folderPath, true));
17008
+ if (lookupsStopped || lookupError) {
17009
+ await recordUnchecked(lookupError, kind, name, directCloudKey);
17010
+ continue;
17011
+ }
16285
17012
  const resolvedType = identity.type ?? rcsMatch?.type ?? metadata?.type;
16286
17013
  if (!rcsMatch) {
16287
17014
  if (isConnection) {
@@ -16300,30 +17027,48 @@ async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTy
16300
17027
  }
16301
17028
  if (!isConnection && rcsMatch.key && knownResourceKeys.has(rcsMatch.key.toLowerCase())) {
16302
17029
  result.skipped++;
17030
+ resolvedKeys.add(bindingKey(kind, name));
16303
17031
  continue;
16304
17032
  }
16305
17033
  const callType = isConnection ? binding.metadata?.connector : resolvedType;
16306
- const [importError] = await catchError(builder.addOrUpdateResourceToSolutionAsync({
17034
+ const wasKnown = !!rcsMatch.key && knownResourceKeys.has(rcsMatch.key.toLowerCase());
17035
+ const reference = {
16307
17036
  kind,
16308
17037
  type: callType,
16309
17038
  key: rcsMatch.key,
16310
17039
  name: rcsMatch.name,
16311
17040
  folder: rcsMatch.folder
16312
- }, true));
17041
+ };
17042
+ const [importError] = await catchError(wasKnown ? refreshKnownResource(services, builder, reference, overwrittenKeys) : builder.addOrUpdateResourceToSolutionAsync(reference, true));
16313
17043
  if (!importError) {
17044
+ resolvedKeys.add(bindingKey(kind, directCloudKey ?? name));
17045
+ if (wasKnown) {
17046
+ result.skipped++;
17047
+ logger.info(`Refreshed ${kind} "${rcsMatch.name}" (key: ${rcsMatch.key}), already in solution`);
17048
+ continue;
17049
+ }
16314
17050
  if (rcsMatch.key) {
16315
17051
  knownResourceKeys.add(rcsMatch.key.toLowerCase());
17052
+ overwrittenKeys.add(rcsMatch.key.toLowerCase());
16316
17053
  }
16317
17054
  result.imported++;
16318
17055
  logger.info(`Imported ${kind} "${rcsMatch.name}" (key: ${rcsMatch.key}) into solution`);
16319
17056
  continue;
16320
17057
  }
17058
+ if (stopsCatalogLookups(classifyCatalogFailure(importError))) {
17059
+ await recordUnchecked(importError, kind, name, directCloudKey);
17060
+ continue;
17061
+ }
16321
17062
  if (isConnection) {
16322
- result.warnings.push(`Failed to import connection ${directCloudKey}: ${importError.message}`);
16323
- logger.warn(`Failed to import connection ${directCloudKey}: ${importError.message}`);
17063
+ const failedStep = importError instanceof OverwriteRefreshError ? "refresh the debug overwrite for" : "import";
17064
+ const warning = `Failed to ${failedStep} connection ${directCloudKey}: ${importError.message}`;
17065
+ result.warnings.push(warning);
17066
+ logger.warn(warning);
16324
17067
  continue;
16325
17068
  }
16326
- logger.warn(`Failed to import ${kind} "${name}" from Orchestrator: ${importError.message}. Will create locally instead.`);
17069
+ const importWarning = `Failed to import ${kind} "${name}" from Orchestrator: ${importError.message}. Created it locally instead; link it before deploy if it must point at the cloud resource.`;
17070
+ result.warnings.push(importWarning);
17071
+ logger.warn(importWarning);
16327
17072
  virtualCandidates.push({
16328
17073
  binding,
16329
17074
  kind,
@@ -16342,11 +17087,29 @@ async function syncResourcesFromBindings(solutionDir, projectPaths, projectSubTy
16342
17087
  return true;
16343
17088
  });
16344
17089
  for (const candidate of dedupedVirtuals) {
16345
- const [syncError] = await catchError(createVirtualForBinding(builder, candidate.binding, candidate.kind, candidate.type, candidate.metadata, candidate.name, candidate.folderPath, result));
17090
+ const [syncError, created] = await catchError(createVirtualForBinding(builder, candidate.binding, candidate.kind, candidate.type, candidate.metadata, candidate.name, candidate.folderPath, result));
16346
17091
  if (syncError) {
16347
17092
  logger.warn(`Failed to create virtual ${candidate.kind}/${candidate.name}: ${syncError.message}`);
17093
+ } else if (created) {
17094
+ resolvedKeys.add(bindingKey(candidate.kind, candidate.name));
16348
17095
  }
16349
17096
  }
17097
+ if (result.catalogLookupFailure) {
17098
+ const seen = new Set;
17099
+ result.unresolved = result.unresolved.filter((b) => {
17100
+ const key = bindingKey(b.kind, b.name);
17101
+ if (resolvedKeys.has(key)) {
17102
+ keptUnchecked++;
17103
+ result.skipped++;
17104
+ return false;
17105
+ }
17106
+ if (seen.has(key))
17107
+ return false;
17108
+ seen.add(key);
17109
+ return true;
17110
+ });
17111
+ result.warnings.push(catalogLookupWarning(result.catalogLookupFailure, keptUnchecked, result.unresolved));
17112
+ }
16350
17113
  const saveError = await saveAndDisposeBuilder(builder, solutionDir);
16351
17114
  if (saveError) {
16352
17115
  throw new Error(`Failed to save solution changes: ${saveError.message}`);
@@ -16374,6 +17137,43 @@ async function pruneMemberClones(builder, memberProjectKeys, result) {
16374
17137
  logger.info(`Removed duplicate ${clone.kind} "${clone.name}" (key: ${clone.key}) — the solution provisions this project itself`);
16375
17138
  }
16376
17139
  }
17140
+ async function isUncheckedBindingCovered(builder, knownResourceKeys, kind, name, directCloudKey) {
17141
+ if (directCloudKey) {
17142
+ return knownResourceKeys.has(directCloudKey.toLowerCase());
17143
+ }
17144
+ const solution = await builder.context.loadAsync();
17145
+ return !!findMatchingLocalResource(solution.resources ?? [], kind, name, undefined);
17146
+ }
17147
+ async function refreshKnownResource(services, builder, reference, overwrittenKeys) {
17148
+ const solution = await builder.context.loadAsync();
17149
+ const referenceKey = reference.key.toLowerCase();
17150
+ const existing = (solution.resources ?? []).find((resource) => resource.key?.toLowerCase() === referenceKey);
17151
+ const mediator = services.container.resolve(Tokens.IMediator);
17152
+ const response = await mediator.sendCommandAsync(new AddOrUpdateResourceToSolutionCommand(builder.context, reference, true, existing?.key));
17153
+ const sdkWroteOverwrite = response.saved && existing?.key === reference.key;
17154
+ if (!existing || sdkWroteOverwrite || overwrittenKeys.has(referenceKey)) {
17155
+ overwrittenKeys.add(referenceKey);
17156
+ return response;
17157
+ }
17158
+ const [overwriteError] = await catchError(refreshOverwrite(services, builder, reference, existing.key));
17159
+ if (overwriteError)
17160
+ throw new OverwriteRefreshError(overwriteError.message);
17161
+ overwrittenKeys.add(referenceKey);
17162
+ return response;
17163
+ }
17164
+ async function refreshOverwrite(services, builder, reference, solutionResourceKey) {
17165
+ const importer = services.container.resolve(Tokens.IImportResourceHelper);
17166
+ const payload = await importer.exportResourceAsync(reference);
17167
+ const referenceKey = reference.key.toLowerCase();
17168
+ const overwrite = [...payload.overwrites].find(([key]) => key.toLowerCase() === referenceKey)?.[1];
17169
+ if (!overwrite) {
17170
+ throw new Error(`Overwrite not found for resource key '${reference.key}' in exported payload`);
17171
+ }
17172
+ const overwrites = services.container.resolve(Tokens.IResourceOverwritesService);
17173
+ await overwrites.manageSolutionOverwritesAsync(builder.context, [
17174
+ { solutionResourceKey, overwrite }
17175
+ ]);
17176
+ }
16377
17177
  async function saveAndDisposeBuilder(builder, solutionDir) {
16378
17178
  const context = builder.context;
16379
17179
  if (!context?.forceSaveChangesAsync) {
@@ -16443,11 +17243,11 @@ async function createVirtualForBinding(builder, _binding, kind, type, metadata,
16443
17243
  if (alreadyVirtualized) {
16444
17244
  result.skipped++;
16445
17245
  logger.info(`Skipping virtual ${kind} "${name}" — existing resource "${alreadyVirtualized.name}" in solution_folder already covers this binding (requested folder "${folderPath}")`);
16446
- return;
17246
+ return true;
16447
17247
  }
16448
17248
  const minted = await mintVirtualResource(builder, kind, type, name, metadata);
16449
17249
  if (!minted)
16450
- return;
17250
+ return false;
16451
17251
  result.created++;
16452
17252
  logger.info(`Created ${kind} "${name}" in solution`);
16453
17253
  if (!virtualizable) {
@@ -16455,6 +17255,7 @@ async function createVirtualForBinding(builder, _binding, kind, type, metadata,
16455
17255
  result.warnings.push(warning);
16456
17256
  logger.warn(warning);
16457
17257
  }
17258
+ return true;
16458
17259
  }
16459
17260
  async function findResourceByKeyInRcs(builder, kind, expectedKey, folderPath, propagateErrors = false) {
16460
17261
  const expectedLower = expectedKey.toLowerCase();
@@ -16532,8 +17333,8 @@ async function searchRcsResourcesStrict(builder, kind, name) {
16532
17333
  } while (pageCursor);
16533
17334
  return allMatches;
16534
17335
  }
16535
- async function findResourceInRcs(builder, kind, name, folderPath) {
16536
- const allMatches = await searchRcsResources(builder, kind, name);
17336
+ async function findResourceInRcs(builder, kind, name, folderPath, propagateErrors = false) {
17337
+ const allMatches = propagateErrors ? await searchRcsResourcesStrict(builder, kind, name) : await searchRcsResources(builder, kind, name);
16537
17338
  if (allMatches.length === 0) {
16538
17339
  return;
16539
17340
  }
@@ -16631,9 +17432,15 @@ async function readUiprojName(uiprojPath) {
16631
17432
  return;
16632
17433
  }
16633
17434
  }
17435
+ async function snapshotResourceIdentities(builder) {
17436
+ const [loadError, solution] = await catchError(builder.context.loadAsync());
17437
+ if (loadError || !solution)
17438
+ return;
17439
+ return new Set((solution.resources ?? []).map((resource) => resource.key ? resource.key.toLowerCase() : `${resource.kind}:${resource.name}`.toLowerCase()));
17440
+ }
16634
17441
  async function reconcileSolutionProjects(builder, solutionDir, projectSubTypes) {
16635
17442
  const fs = getFileSystem();
16636
- const outcome = { projectsCount: 0 };
17443
+ const outcome = { projectsCount: 0, resourcesAdded: 0 };
16637
17444
  const uipxProjects = await readUipxProjects(solutionDir);
16638
17445
  const projectDetails = uipxProjects.flatMap((project) => {
16639
17446
  const reconcileType = mapUipxTypeToReconcileType(project.type);
@@ -16651,6 +17458,7 @@ async function reconcileSolutionProjects(builder, solutionDir, projectSubTypes)
16651
17458
  if (projectDetails.length === 0)
16652
17459
  return outcome;
16653
17460
  const solutionName = fs.path.basename(solutionDir);
17461
+ const before = await snapshotResourceIdentities(builder);
16654
17462
  const [reconcileError] = await catchError(builder.reconcileProjectsAsync({
16655
17463
  solutionName,
16656
17464
  projects: projectDetails
@@ -16660,6 +17468,10 @@ async function reconcileSolutionProjects(builder, solutionDir, projectSubTypes)
16660
17468
  return outcome;
16661
17469
  }
16662
17470
  outcome.projectsCount = projectDetails.length;
17471
+ const after = before && await snapshotResourceIdentities(builder);
17472
+ if (before && after) {
17473
+ outcome.resourcesAdded = [...after].filter((identity) => !before.has(identity)).length;
17474
+ }
16663
17475
  logger.info(`Reconciled ${projectDetails.length} .uipx project(s) in solution ${solutionName}`);
16664
17476
  return outcome;
16665
17477
  }
@@ -16701,12 +17513,48 @@ function findBindingsSchemaError(content) {
16701
17513
  }
16702
17514
  return null;
16703
17515
  }
16704
- async function collectBindings(solutionDir, projectPaths, bindingsJsonFallbackDirs, serializer) {
17516
+ function bindingSources(solutionDir, projectPaths, projects, projectBindings) {
17517
+ const sources = [{ directory: solutionDir }];
17518
+ const fileDirectories = new Set([solutionDir]);
17519
+ const contributedIds = new Set;
17520
+ for (const directory of new Set(projectPaths)) {
17521
+ const owners = projects.filter((project) => project.path === directory);
17522
+ for (const project of owners) {
17523
+ const bindings = projectBindings?.get(project.id);
17524
+ if (bindings === undefined || contributedIds.has(project.id))
17525
+ continue;
17526
+ contributedIds.add(project.id);
17527
+ sources.push({
17528
+ directory,
17529
+ contribution: { projectId: project.id, bindings }
17530
+ });
17531
+ }
17532
+ const needsFile = owners.length === 0 || owners.some((project) => !projectBindings?.has(project.id));
17533
+ if (needsFile && !fileDirectories.has(directory)) {
17534
+ fileDirectories.add(directory);
17535
+ sources.push({ directory });
17536
+ }
17537
+ }
17538
+ return sources;
17539
+ }
17540
+ async function collectBindings(bindingsJsonFallbackDirs, serializer, sources) {
16705
17541
  const fs = getFileSystem();
16706
17542
  const allBindings = [];
16707
17543
  const parseErrors = [];
16708
- const candidateDirs = [solutionDir, ...projectPaths];
16709
- for (const dir of candidateDirs) {
17544
+ for (const { directory: dir, contribution } of sources) {
17545
+ if (contribution) {
17546
+ if (contribution.bindings.length === 0)
17547
+ continue;
17548
+ const parsed2 = deserializeBindings(JSON.stringify({
17549
+ version: "2.0",
17550
+ resources: contribution.bindings
17551
+ }), `${dir} (bindings contributed by the project's tool; project ${contribution.projectId})`, serializer);
17552
+ if ("error" in parsed2)
17553
+ parseErrors.push(parsed2.error);
17554
+ else
17555
+ allBindings.push(...parsed2.resources);
17556
+ continue;
17557
+ }
16710
17558
  const v2Path = fs.path.join(dir, "bindings_v2.json");
16711
17559
  let bindingsPath = v2Path;
16712
17560
  let exists = await fs.exists(v2Path);
@@ -16725,37 +17573,44 @@ async function collectBindings(solutionDir, projectPaths, bindingsJsonFallbackDi
16725
17573
  });
16726
17574
  continue;
16727
17575
  }
16728
- const decoded = new TextDecoder().decode(content);
16729
- let success;
16730
- let metadata;
16731
- try {
16732
- const result = serializer.tryDeserialize(decoded);
16733
- success = result.success;
16734
- metadata = result.metadata;
16735
- } catch (err) {
16736
- parseErrors.push({
16737
- path: bindingsPath,
17576
+ const parsed = deserializeBindings(new TextDecoder().decode(content), bindingsPath, serializer);
17577
+ if ("error" in parsed)
17578
+ parseErrors.push(parsed.error);
17579
+ else
17580
+ allBindings.push(...parsed.resources);
17581
+ }
17582
+ return { bindings: allBindings, parseErrors };
17583
+ }
17584
+ function deserializeBindings(decoded, source, serializer) {
17585
+ let success;
17586
+ let metadata;
17587
+ try {
17588
+ const result = serializer.tryDeserialize(decoded);
17589
+ success = result.success;
17590
+ metadata = result.metadata;
17591
+ } catch (err) {
17592
+ return {
17593
+ error: {
17594
+ path: source,
16738
17595
  reason: findBindingsSchemaError(decoded) ?? `does not match the expected v2 bindings schema — check each resource's 'kind' and required fields${err instanceof Error ? ` (${err.message})` : ""}`
16739
- });
16740
- continue;
16741
- }
16742
- if (!success) {
16743
- parseErrors.push({
16744
- path: bindingsPath,
17596
+ }
17597
+ };
17598
+ }
17599
+ if (!success) {
17600
+ return {
17601
+ error: {
17602
+ path: source,
16745
17603
  reason: findBindingsSchemaError(decoded) ?? "does not match the expected v2 bindings schema (the serializer rejected it)"
16746
- });
16747
- continue;
16748
- }
16749
- if (!metadata?.resources?.length) {
16750
- continue;
16751
- }
16752
- allBindings.push(...metadata.resources);
17604
+ }
17605
+ };
16753
17606
  }
16754
- return { bindings: allBindings, parseErrors };
17607
+ return { resources: metadata?.resources ?? [] };
16755
17608
  }
16756
- async function syncAndLog(solutionDir, projectSubTypes) {
16757
- const [syncError, syncResult] = await catchError(syncResourcesFromBindings(solutionDir, undefined, projectSubTypes));
17609
+ async function syncAndLog(solutionDir, projectSubTypes, options) {
17610
+ const [syncError, syncResult] = await catchError(syncResourcesFromBindings(solutionDir, undefined, projectSubTypes, options?.projectBindings));
16758
17611
  if (syncError) {
17612
+ if (options?.failOnUnresolved)
17613
+ throw syncError;
16759
17614
  logger.warn(`Resource sync failed: ${syncError.message}. Continuing.`);
16760
17615
  return;
16761
17616
  }
@@ -16765,6 +17620,9 @@ async function syncAndLog(solutionDir, projectSubTypes) {
16765
17620
  for (const warning of syncResult.warnings) {
16766
17621
  logger.warn(warning);
16767
17622
  }
17623
+ if (options?.failOnUnresolved && syncResult.catalogLookupFailure && syncResult.unresolved.length > 0) {
17624
+ throw new CatalogLookupError(syncResult.catalogLookupFailure, syncResult.unresolved);
17625
+ }
16768
17626
  }
16769
17627
 
16770
17628
  // ../solution-sdk/src/resources/services/resource-refresh-service.ts
@@ -16801,7 +17659,11 @@ async function resourceRefreshAsync(solutionPath = ".", options = {}) {
16801
17659
  const resolverWarnings = subTypesError ? [
16802
17660
  `Could not resolve project subTypes: ${subTypesError.message}. Project artefacts for types that need a variant were left as they are; fix the tool install and re-run 'uip solution resources refresh'.`
16803
17661
  ] : [];
16804
- const [syncError, result] = await catchError(syncResourcesFromBindings(resolvedPath, undefined, projectSubTypes ?? new Map));
17662
+ const [bindingsError, projectBindings] = await catchError(options.resolveProjectBindingsAsync?.() ?? Promise.resolve(new Map));
17663
+ if (bindingsError) {
17664
+ resolverWarnings.push(`Could not read the bindings projects contribute: ${bindingsError.message}. Those projects were synced from any bindings_v2.json on disk instead; fix the tool install and re-run 'uip solution resources refresh'.`);
17665
+ }
17666
+ const [syncError, result] = await catchError(syncResourcesFromBindings(resolvedPath, undefined, projectSubTypes ?? new Map, projectBindings ?? new Map));
16805
17667
  if (syncError) {
16806
17668
  return {
16807
17669
  ok: false,
@@ -16815,6 +17677,7 @@ async function resourceRefreshAsync(solutionPath = ".", options = {}) {
16815
17677
  imported: result.imported,
16816
17678
  skipped: result.skipped,
16817
17679
  pruned: result.pruned,
17680
+ projectResourcesCreated: result.projectResourcesCreated,
16818
17681
  warnings: [...resolverWarnings, ...result.warnings]
16819
17682
  };
16820
17683
  }
@@ -16996,6 +17859,7 @@ function sortKeysDeep(value) {
16996
17859
  return sorted;
16997
17860
  }
16998
17861
  export {
17862
+ CatalogLookupError,
16999
17863
  EntryPointSpecEnhancer,
17000
17864
  MAX_RESOURCE_NAME_LENGTH,
17001
17865
  ProjectManifestError,
@@ -17008,7 +17872,9 @@ export {
17008
17872
  createProjectInSolutionBuilder,
17009
17873
  createResourceBuilderServices,
17010
17874
  createResourceKindMetadataResolver,
17875
+ exportResourceConfigurationsAsync,
17011
17876
  exportResourceDefinitionAsync,
17877
+ findCatalogEntitiesAsync,
17012
17878
  findCatalogEntityAsync,
17013
17879
  findMatchingLocalResource,
17014
17880
  findMatchingMemberResource,
@@ -17016,21 +17882,26 @@ export {
17016
17882
  findProjectFile,
17017
17883
  findResourceByKeyInRcs,
17018
17884
  findResourceInRcs,
17885
+ findResourcesByNameAsync,
17019
17886
  formatResourceSubtypes,
17020
17887
  getRemoteResourceClients,
17021
17888
  hasAnyTemplateRow,
17022
17889
  hasBareTemplateRow,
17023
17890
  isMissingProjectTypeError,
17024
17891
  isProjectManifestError,
17892
+ isResourceKeyNotFound,
17025
17893
  normalizeFolderPath,
17026
17894
  normalizeResourceCasing,
17027
17895
  normalizeResourceFileCasing,
17028
17896
  readProjectFile,
17897
+ readResourceConfigurationAsync,
17898
+ readResourceConfigurationsAsync,
17029
17899
  readSolutionFile,
17030
17900
  readSolutionManifest,
17031
17901
  readSpecEntryPoints,
17032
17902
  readSpecProperty,
17033
17903
  readUipxProjects,
17904
+ refreshArtefactSpecsAsync,
17034
17905
  resolveProjectDirFromManifest,
17035
17906
  resolveResourceKindMetadata,
17036
17907
  resolveSolutionFilePath,
@@ -17050,4 +17921,4 @@ export {
17050
17921
  writeSolutionFile
17051
17922
  };
17052
17923
 
17053
- //# debugId=341DEBC9DC0AE67064756E2164756E21
17924
+ //# debugId=8E03505B75E11F7864756E2164756E21