@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.
- package/dist/THIRD-PARTY-NOTICES.md +24 -11
- package/dist/{authoring-6ckkzfc9.js → authoring-kqh34zzm.js} +49 -30
- package/dist/{business-rule-export-kg5bk8aw.js → business-rule-export-ey588rv7.js} +2 -2
- package/dist/canvas-notes-86fxx1t8.js +19 -0
- package/dist/{case-api-rvamfn02.js → case-api-sme7esce.js} +6 -6
- package/dist/case-bindings-service-cht20gqt.js +430 -0
- package/dist/case-debug-solution-projects-h3w2nx0a.js +34 -0
- package/dist/{case-debug-studio-web-service-xxfesw4v.js → case-debug-studio-web-service-3mkrtaet.js} +16 -10
- package/dist/{case-described-io-service-14hdnqcc.js → case-described-io-service-dx1f4nxe.js} +37 -11
- package/dist/case-event-trigger-bindings-g9ftnm4x.js +16 -0
- package/dist/{case-format-service-yb48785t.js → case-format-service-6aew6tqc.js} +2 -2
- package/dist/{case-pack-service-9185h6ez.js → case-pack-service-pqq8wnfd.js} +6 -6
- package/dist/case-schema-version-h820ne16.js +20 -0
- package/dist/{case-shape-reader-mw58avr0.js → case-shape-reader-dsbraetf.js} +1 -1
- package/dist/{case-splice-service-tkmb7xjp.js → case-splice-service-s5gccctq.js} +53 -8
- package/dist/{case-validate-service-c84e2bhv.js → case-validate-service-rey6btew.js} +128 -42
- package/dist/{connector-enrichment-service-hfv0kwht.js → connector-enrichment-service-crqs2216.js} +23 -20
- package/dist/{connector-lookup-service-whgjceyj.js → connector-lookup-service-dwv8q5eh.js} +6 -6
- package/dist/connector-task-shape-mpazkf7s.js +14 -0
- package/dist/{connector-task-spec-k0cwavrm.js → connector-task-spec-trs4tcb3.js} +196 -40
- package/dist/{de-MUJPA4EB-dpg7t2rw.js → de-UZI7FJDO-mwvc4cxe.js} +29 -2
- package/dist/{de-FGHEJRCI-rv513mfh.js → de-WLW6KWOJ-2qnsqdtw.js} +238 -31
- package/dist/{debug-service-ch3v6jmm.js → debug-service-7q98j726.js} +3 -3
- package/dist/{embedded-file-reader-v8c2yj2a.js → embedded-file-reader-r66242ey.js} +2 -2
- package/dist/{en-FBPVNKFN-dqt573xn.js → en-EJCBA3LK-dtpdghgj.js} +12 -4
- package/dist/{en-BWGKA5OE-1qkvb9rn.js → en-M7GQYBV2-5nfmpnfz.js} +88 -6
- package/dist/{enrichment-service-3f1kygjs.js → enrichment-service-hv7ff88p.js} +56 -12
- package/dist/{es-7SE7HX2X-8yh1aj2y.js → es-4UBUTCQA-m1ytpyx2.js} +29 -2
- package/dist/{es-KR3ZSNMP-84zphx0x.js → es-5THCNRFN-tqwyrdgy.js} +235 -28
- package/dist/{es-MX-2MYFZU7X-3rek4r73.js → es-MX-5RELIXKI-9jhqtddc.js} +29 -2
- package/dist/{es-MX-XXZJGC4R-2mr8jtgm.js → es-MX-TWZBRAXK-gqd9swzw.js} +237 -30
- package/dist/filter-engine-7ep90g7f.js +11 -0
- package/dist/{fr-Y6NPVODW-8vr1ja4b.js → fr-CERONSRC-edpxhbmb.js} +237 -30
- package/dist/{fr-MDFKNZ4C-h4a122k9.js → fr-VBM5WRC2-63z7w4mh.js} +29 -2
- package/dist/index-332n0kxj.js +282 -0
- package/dist/{index-wmffgzmr.js → index-5dxh9z60.js} +21751 -11098
- package/dist/{index-aw2gqqat.js → index-a2fvrrth.js} +4 -4
- package/dist/{index-4yanx3rn.js → index-ekwtgx7y.js} +1089 -218
- package/dist/{index-ng2f77my.js → index-fyc0k5dd.js} +985 -617
- package/dist/index-n9qvnx4x.js +29 -0
- package/dist/{index-hhsf00x8.js → index-ngs0a2he.js} +1 -1
- package/dist/{index-j2r3jb6c.js → index-xq6ajhgq.js} +2 -2
- package/dist/index.js +12 -12
- package/dist/init-entry-points-hhpv3e3f.js +98 -0
- package/dist/{input-reader-1tcqt27f.js → input-reader-c7wz8ra2.js} +3 -3
- package/dist/{ja-UTQEAP34-8e0q6swp.js → ja-43QL7CGO-c3q8gre9.js} +29 -2
- package/dist/{ja-Q5PXKJ2V-p4msxzjd.js → ja-U2MCNHGT-gz0ap1jk.js} +235 -28
- package/dist/{known-types-0h9kqwyy.js → known-types-jvkdgmzz.js} +5 -4
- package/dist/{ko-AXCHW2OK-askct7f6.js → ko-TLL6Z6CD-wrt3n8a9.js} +29 -2
- package/dist/{ko-AYBDSRZG-41mdmsg1.js → ko-XAUYQWDR-zp81gjp4.js} +237 -30
- package/dist/localSolutionDiscovery-yyx234ak.js +13 -0
- package/dist/migration-diagnosis-ns5cw4e3.js +99 -0
- package/dist/{node-strategy-5pz40tee.js → node-strategy-v442hwgd.js} +1 -1
- package/dist/node-sync-service-1wkcyn1n.js +57 -0
- package/dist/out-target-wjgmna0r.js +111 -0
- package/dist/{packager-tool-85q4f3pq.js → packager-tool-1pcmxqny.js} +3 -3
- package/dist/{packager-tool-8a9yqfq7.js → packager-tool-1yfw674x.js} +4 -2
- package/dist/{packager-tool-pdhhzfr5.js → packager-tool-29x6vran.js} +296 -417
- package/dist/packager-tool-2sn7d8fd.js +41 -0
- package/dist/packager-tool-4p11fvf4.js +92 -0
- package/dist/{packager-tool-25hng8h4.js → packager-tool-4rtktkhv.js} +16211 -13084
- package/dist/{packager-tool-yfm83bzd.js → packager-tool-67vy1fz3.js} +4 -3
- package/dist/{packager-tool-d88rqwk8.js → packager-tool-6z1hsm2h.js} +13 -5
- package/dist/packager-tool-7hw344bt.js +107 -0
- package/dist/{packager-tool-3q3d1hk8.js → packager-tool-83v804p7.js} +56 -6
- package/dist/{packager-tool-00y70spr.js → packager-tool-87y6xw3a.js} +2 -1
- package/dist/packager-tool-93mdeqay.js +18 -0
- package/dist/{packager-tool-64rg5ekd.js → packager-tool-9e59z4d6.js} +75 -7
- package/dist/{packager-tool-vepqrsse.js → packager-tool-9kf3fqtr.js} +2 -2
- package/dist/packager-tool-9kvkzc05.js +74 -0
- package/dist/{packager-tool-s6619wtx.js → packager-tool-9sd483vs.js} +2 -2
- package/dist/{packager-tool-f78ntj5g.js → packager-tool-9y1w2wds.js} +51 -6
- package/dist/packager-tool-a17g0pj1.js +62 -0
- package/dist/{packager-tool-167qap9m.js → packager-tool-aagnvyba.js} +845 -38
- package/dist/{packager-tool-0p6dbsp0.js → packager-tool-c5q10254.js} +5 -5
- package/dist/{packager-tool-wj9d9mqe.js → packager-tool-e15kqpyh.js} +12 -13
- package/dist/{packager-tool-c31qx8kc.js → packager-tool-ezds6t5e.js} +2 -2
- package/dist/{packager-tool-d3zvghjd.js → packager-tool-f2z2dscy.js} +308 -120
- package/dist/{packager-tool-hvzjm2nk.js → packager-tool-f8vwy92w.js} +2093 -5805
- package/dist/{packager-tool-rgpdaxbx.js → packager-tool-gx2cer6a.js} +5385 -1098
- package/dist/{packager-tool-xdxr3ync.js → packager-tool-hdxtgckw.js} +11 -1
- package/dist/{packager-tool-mr149jsw.js → packager-tool-k5cpxdm4.js} +17 -7
- package/dist/packager-tool-k6jbedyc.js +69 -0
- package/dist/packager-tool-kdhey8gz.js +153 -0
- package/dist/{packager-tool-cenvh23g.js → packager-tool-kyrm4e5m.js} +718 -87
- package/dist/packager-tool-mqy97y5f.js +52 -0
- package/dist/{packager-tool-jfysbxdt.js → packager-tool-mzf4gmph.js} +4 -4
- package/dist/packager-tool-n7w9wx62.js +25 -0
- package/dist/{packager-tool-7q6z6npd.js → packager-tool-pcvhcn2k.js} +93 -11
- package/dist/packager-tool-r0x3qh59.js +307 -0
- package/dist/{packager-tool-w1b5pyj6.js → packager-tool-r6b5ktzb.js} +730 -14
- package/dist/{packager-tool-zbrda9sn.js → packager-tool-rk25wp3c.js} +1 -1
- package/dist/{packager-tool-xcd87qyx.js → packager-tool-v2kcgjbf.js} +2 -3
- package/dist/{case-bindings-service-d9vezn69.js → packager-tool-wekqkmgn.js} +20 -231
- package/dist/packager-tool-yct6zp4m.js +335 -0
- package/dist/{packager-tool-kpqr938m.js → packager-tool-ydyvtknp.js} +26 -3
- package/dist/{packager-tool-v99ygh9f.js → packager-tool-yn33pw57.js} +124 -58
- package/dist/{packager-tool-4rqd21wc.js → packager-tool-yn7r7zq2.js} +19 -5
- package/dist/{packager-tool-cmwets3m.js → packager-tool-zf8f9pmm.js} +1 -1
- package/dist/packager-tool.js +3 -3
- package/dist/{project-artifacts-rng5m6r2.js → project-artifacts-bgyyb0dm.js} +1 -1
- package/dist/{pt-BR-TKHNHMET-sn91xyq0.js → pt-BR-GNQNAAZ2-xadharv4.js} +237 -30
- package/dist/{pt-BR-Y6K6XHXK-mp3hwhw1.js → pt-BR-USP2T7GD-pedn77m1.js} +29 -2
- package/dist/{pt-3DIO5QWG-59b3f4bc.js → pt-RMIAKZB4-67enhx3m.js} +29 -2
- package/dist/{pt-ROXU257Y-2f6bxev4.js → pt-TO2DARY2-ftcce1bv.js} +237 -30
- package/dist/{resolved-check-p99hysaw.js → resolved-check-aqw7568y.js} +1 -1
- package/dist/{resourcesSyncService-zwjyp1qx.js → resourcesSyncService-d302jnap.js} +32 -170
- package/dist/{ro-BWR3ONRR-vzx3hy8a.js → ro-GHOBYW2S-mhnqsgaa.js} +29 -2
- package/dist/{ro-AVAWPKOO-b89pw79r.js → ro-WUYJV6OW-a8d9qy1n.js} +235 -28
- package/dist/{sdd-convert-service-vf0ps358.js → sdd-convert-service-8jpew7vz.js} +686 -445
- package/dist/{sdd-lookup-dwzpvvwn.js → sdd-lookup-fe900sdb.js} +2 -2
- package/dist/{sdd-resolve-service-mjqad2nn.js → sdd-resolve-service-qdtmxw9b.js} +38 -13
- package/dist/sdd-resolve-siblings-6kfxc2t6.js +53 -0
- package/dist/{solution-auth-kddmbm0p.js → solution-auth-30yycqtv.js} +3 -3
- package/dist/solution-discovery-g6ksnrg1.js +38 -0
- package/dist/{strict-case-rules-tz37bspw.js → strict-case-rules-4tjcaznr.js} +3 -2
- package/dist/{strict-entry-points-v14d7y50.js → strict-entry-points-g2pd4mf4.js} +29 -1
- package/dist/{strict-sdd-audit-4aqdeh59.js → strict-sdd-audit-q7tb9yj7.js} +7 -5
- package/dist/task-type-declaration-7a8fqdvs.js +46 -0
- package/dist/tool.js +12 -12
- package/dist/{tr-5IIHSFW5-hw4cewew.js → tr-GDTLECMM-k5fhmq13.js} +29 -2
- package/dist/{tr-JMIP7ZSL-c39b6pe4.js → tr-M3F5A6AU-bb0tg39m.js} +235 -28
- package/dist/{trigger-enrichment-service-g3vt051f.js → trigger-enrichment-service-sj0p2d1j.js} +23 -20
- package/dist/trigger-entry-point-id-yhqwnkx9.js +15 -0
- package/dist/{zh-CN-IFFXSEJS-9wm9gmrv.js → zh-CN-C5G4PC7C-ds9gkptg.js} +235 -28
- package/dist/{zh-CN-R2KU4U5L-tc1hat59.js → zh-CN-I5D7WHBD-sr5h0a98.js} +29 -2
- package/dist/{zh-TW-GNKMELBF-j674515r.js → zh-TW-2AVLM723-288pkc1z.js} +29 -2
- package/dist/{zh-TW-IYBNYAMG-8727c7v2.js → zh-TW-62HZIG6O-787kdwex.js} +234 -27
- package/package.json +2 -2
- package/dist/migration-diagnosis-ag2sgd1e.js +0 -71
- package/dist/node-sync-service-2tfrgbjs.js +0 -36
- package/dist/out-target-jakehnd3.js +0 -70
- package/dist/packager-tool-57pzrd0g.js +0 -32
- package/dist/packager-tool-dthjwajc.js +0 -13
- 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-
|
|
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-
|
|
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-
|
|
35
|
+
} from "./packager-tool-83v804p7.js";
|
|
36
36
|
import {
|
|
37
37
|
getFileSystem
|
|
38
|
-
} from "./packager-tool-
|
|
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
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
let
|
|
3463
|
-
let
|
|
3464
|
-
|
|
3465
|
-
let
|
|
3466
|
-
|
|
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
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
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
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
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
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
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
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
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
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
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 (
|
|
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
|
-
|
|
4278
|
-
const
|
|
4279
|
-
if (
|
|
4280
|
-
|
|
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
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
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
|
|
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,
|
|
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]
|
|
16558
|
+
if (sameIgnoringCase(target[kindIndex], kind)) {
|
|
15981
16559
|
target[kindIndex] = lowerFirstChar(kind);
|
|
15982
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
}
|
|
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
|
-
|
|
16323
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
16709
|
-
|
|
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
|
|
16729
|
-
|
|
16730
|
-
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
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
|
-
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
|
|
16744
|
-
|
|
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
|
-
|
|
16748
|
-
}
|
|
16749
|
-
if (!metadata?.resources?.length) {
|
|
16750
|
-
continue;
|
|
16751
|
-
}
|
|
16752
|
-
allBindings.push(...metadata.resources);
|
|
17604
|
+
}
|
|
17605
|
+
};
|
|
16753
17606
|
}
|
|
16754
|
-
return {
|
|
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 [
|
|
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=
|
|
17924
|
+
//# debugId=8E03505B75E11F7864756E2164756E21
|