@uipath/maestro-builder-sdk 6.31.2 → 6.31.4
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/README.md +5 -1
- package/dist/api-index.md +16 -16
- package/dist/api-members.md +75 -75
- package/dist/check.js +9 -0
- package/dist/decompile-cli.js +36 -10
- package/dist/decompile.js +14 -13
- package/dist/flow-sdk.d.ts +6 -2
- package/dist/loop-version.d.ts +41 -0
- package/dist/loop-version.js +97 -0
- package/dist/registry/curated-overlay.d.ts +63 -28
- package/dist/registry/curated-overlay.js +265 -49
- package/dist/registry/orphans.js +5 -3
- package/dist/serialize.js +10 -21
- package/lib/library-json.samples/index.json +1 -1
- package/lib/library-json.samples/overlay-corrections.json +43 -0
- package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.json +49 -6
- package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.v1def.json +38 -55
- package/package.json +2 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { cp, mkdir, readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { access, cp, mkdir, readdir, readFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, join, relative, sep } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { sortedStrings } from "./compat/compare.js";
|
|
6
|
+
import { jsonClone } from "../core/json-clone.js";
|
|
6
7
|
import { writeJsonFile } from "../core/json-file.js";
|
|
7
8
|
import { consoleReporter } from "./reporter.js";
|
|
8
9
|
/** The corrections and definitions that the raw registry dump does not carry. */
|
|
@@ -33,39 +34,182 @@ export async function curatedOverlayIdentity(overlayPath = bundledOverlayPath())
|
|
|
33
34
|
function entryIdentity(entry) {
|
|
34
35
|
return `${String(entry.nodeType)}\0${String(entry.version)}`;
|
|
35
36
|
}
|
|
37
|
+
/** The ledger of deliberate patches; read here, never copied into a library. */
|
|
38
|
+
export const CORRECTIONS_FILE = "overlay-corrections.json";
|
|
39
|
+
/**
|
|
40
|
+
* What the overlay did to one library, written beside it as a dotfile so a
|
|
41
|
+
* second application (`unpack-library.mjs` applies it twice, once per verb)
|
|
42
|
+
* does not mistake its own patch for "the published library caught up".
|
|
43
|
+
*/
|
|
44
|
+
const RECORD_FILE = ".curated-overlay.json";
|
|
45
|
+
/** SDK-owned side-tables the published library does not carry; always copied. */
|
|
46
|
+
const SIDE_TABLES = new Set(["list-envelopes.json", "invariant-collections.json"]);
|
|
36
47
|
/** The sidecar that travels with an entry file, and has no index row of its own. */
|
|
37
48
|
function sidecarOf(rel) {
|
|
38
49
|
return `${rel.slice(0, -".json".length)}.v1def.json`;
|
|
39
50
|
}
|
|
51
|
+
function isDict(value) {
|
|
52
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
53
|
+
}
|
|
54
|
+
/** A sidecar is either the definition itself or a one-element array of it. */
|
|
55
|
+
function sidecarBody(sidecar) {
|
|
56
|
+
const body = Array.isArray(sidecar) ? sidecar[0] : sidecar;
|
|
57
|
+
return isDict(body) ? body : undefined;
|
|
58
|
+
}
|
|
59
|
+
/** `holder[key].fields`, created when absent, so a patch has an array to add to. */
|
|
60
|
+
function fieldList(holder, key) {
|
|
61
|
+
const section = isDict(holder[key]) ? holder[key] : (holder[key] = {});
|
|
62
|
+
if (!Array.isArray(section.fields))
|
|
63
|
+
section.fields = [];
|
|
64
|
+
return section.fields;
|
|
65
|
+
}
|
|
66
|
+
function fieldNames(fields) {
|
|
67
|
+
return new Set((Array.isArray(fields) ? fields : [])
|
|
68
|
+
.filter(isDict)
|
|
69
|
+
.map((field) => String(field.name)));
|
|
70
|
+
}
|
|
71
|
+
async function readJson(path) {
|
|
72
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
73
|
+
}
|
|
74
|
+
async function exists(path) {
|
|
75
|
+
try {
|
|
76
|
+
await access(path);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The bundled corrections, checked against the overlay they ship in. A row
|
|
85
|
+
* that names no indexed overlay entry, or a field that entry does not define,
|
|
86
|
+
* is a fault in the SDK's own data, so it throws rather than patching nothing.
|
|
87
|
+
*/
|
|
88
|
+
export async function readOverlayCorrections(overlayPath) {
|
|
89
|
+
const file = join(overlayPath, CORRECTIONS_FILE);
|
|
90
|
+
if (!(await exists(file)))
|
|
91
|
+
return [];
|
|
92
|
+
const ledger = (await readJson(file));
|
|
93
|
+
const overlayIndex = (await readJson(join(overlayPath, "index.json")));
|
|
94
|
+
const indexed = new Set((overlayIndex.entries ?? []).map((row) => row.path));
|
|
95
|
+
const corrections = ledger.corrections ?? [];
|
|
96
|
+
for (const correction of corrections) {
|
|
97
|
+
const where = `${CORRECTIONS_FILE}: correction ${JSON.stringify(correction.path)}`;
|
|
98
|
+
if (!indexed.has(correction.path)) {
|
|
99
|
+
throw new Error(`${where} names no entry in the overlay's index.json.`);
|
|
100
|
+
}
|
|
101
|
+
if (!correction.inputFields?.length && !correction.sidecarKeys?.length) {
|
|
102
|
+
throw new Error(`${where} patches nothing: give it inputFields or sidecarKeys.`);
|
|
103
|
+
}
|
|
104
|
+
const entry = (await readJson(join(overlayPath, correction.path)));
|
|
105
|
+
const sidecar = sidecarBody(await readJson(join(overlayPath, sidecarOf(correction.path)))) ?? {};
|
|
106
|
+
const entryFields = fieldNames(entry.inputSchema?.fields);
|
|
107
|
+
const sidecarFields = fieldNames(sidecar.inputDefinition?.fields);
|
|
108
|
+
for (const name of correction.inputFields ?? []) {
|
|
109
|
+
if (!entryFields.has(name) || !sidecarFields.has(name)) {
|
|
110
|
+
throw new Error(`${where}: the overlay's copy does not define input field ${JSON.stringify(name)} in both files.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const key of correction.sidecarKeys ?? []) {
|
|
114
|
+
if (!(key in sidecar)) {
|
|
115
|
+
throw new Error(`${where}: the overlay's sidecar has no ${JSON.stringify(key)}.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return corrections;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* sha256 of a correction's entry file and sidecar as they are on disk now (a
|
|
123
|
+
* missing sidecar hashes as absent). The record keeps this for each patch it
|
|
124
|
+
* made, so a later application trusts its own patch only while both files are
|
|
125
|
+
* still the ones it wrote.
|
|
126
|
+
*/
|
|
127
|
+
async function correctionDigest(libraryPath, path) {
|
|
128
|
+
const hash = createHash("sha256");
|
|
129
|
+
hash.update(await readFile(join(libraryPath, path)));
|
|
130
|
+
const sidecarPath = join(libraryPath, sidecarOf(path));
|
|
131
|
+
hash.update("\0");
|
|
132
|
+
hash.update((await exists(sidecarPath)) ? await readFile(sidecarPath) : "<no sidecar>");
|
|
133
|
+
return hash.digest("hex");
|
|
134
|
+
}
|
|
40
135
|
/**
|
|
41
|
-
*
|
|
136
|
+
* Add what `correction` names to the library's own entry and sidecar, from the
|
|
137
|
+
* overlay's copy. Returns the names it added (empty means the published
|
|
138
|
+
* definition already carries every one of them) and how many files it wrote.
|
|
139
|
+
* A library with no sidecar for the entry gets none: only the entry is patched.
|
|
140
|
+
*/
|
|
141
|
+
async function patchCorrection(libraryPath, overlayPath, correction) {
|
|
142
|
+
const sourceEntry = (await readJson(join(overlayPath, correction.path)));
|
|
143
|
+
const sourceSidecar = sidecarBody(await readJson(join(overlayPath, sidecarOf(correction.path)))) ?? {};
|
|
144
|
+
const entryPath = join(libraryPath, correction.path);
|
|
145
|
+
const sidecarPath = join(libraryPath, sidecarOf(correction.path));
|
|
146
|
+
const entry = (await readJson(entryPath));
|
|
147
|
+
const sidecarRaw = (await exists(sidecarPath)) ? await readJson(sidecarPath) : undefined;
|
|
148
|
+
const sidecar = sidecarRaw === undefined ? undefined : sidecarBody(sidecarRaw);
|
|
149
|
+
const added = [];
|
|
150
|
+
const addFields = (target, source, label) => {
|
|
151
|
+
const have = fieldNames(target);
|
|
152
|
+
const byName = new Map((Array.isArray(source) ? source : []).filter(isDict).map((field) => [String(field.name), field]));
|
|
153
|
+
for (const name of correction.inputFields ?? []) {
|
|
154
|
+
if (have.has(name))
|
|
155
|
+
continue;
|
|
156
|
+
target.push(jsonClone(byName.get(name)));
|
|
157
|
+
added.push(`${label}:${name}`);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
addFields(fieldList(entry, "inputSchema"), sourceEntry.inputSchema?.fields, "inputSchema");
|
|
161
|
+
if (sidecar) {
|
|
162
|
+
addFields(fieldList(sidecar, "inputDefinition"), sourceSidecar.inputDefinition?.fields, "inputDefinition");
|
|
163
|
+
for (const key of correction.sidecarKeys ?? []) {
|
|
164
|
+
if (key in sidecar)
|
|
165
|
+
continue;
|
|
166
|
+
sidecar[key] = jsonClone(sourceSidecar[key]);
|
|
167
|
+
added.push(`sidecar:${key}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (added.length === 0)
|
|
171
|
+
return { added, files: 0 };
|
|
172
|
+
writeJsonFile(entryPath, entry);
|
|
173
|
+
if (sidecar)
|
|
174
|
+
writeJsonFile(sidecarPath, sidecarRaw);
|
|
175
|
+
return { added, files: sidecar ? 2 : 1 };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Apply the SDK's curated overlay after extracting the raw registry dump.
|
|
42
179
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* correction changes the referenced file, and a definition absent from the
|
|
46
|
-
* dump (notably connector triggers) is made resolvable by its added index row.
|
|
180
|
+
* THE RULE. The overlay ADDS what the library lacks and never replaces what it
|
|
181
|
+
* carries, apart from the deliberate patches listed in {@link CORRECTIONS_FILE}:
|
|
47
182
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
183
|
+
* - an overlay entry whose (nodeType, version) the library does not index is
|
|
184
|
+
* copied with its sidecar, and its index row is added. This is what makes
|
|
185
|
+
* the connector start triggers resolvable, which the raw dump lacks;
|
|
186
|
+
* - an entry the library indexes at the SAME path is kept as published. The
|
|
187
|
+
* overlay's copy is a snapshot, and the published library moves on: until
|
|
188
|
+
* #1148 every such file was copied over the download while the download's
|
|
189
|
+
* index row stayed, so nine 2026-07 snapshots replaced newer definitions and
|
|
190
|
+
* Outlook `send-email` read `send-mail` (no `saveAsDraft`, no multipart
|
|
191
|
+
* parts) under an index row that said `send-mail-v2`. The entry files carry
|
|
192
|
+
* no date or build number to compare, so "is the published one newer?" is
|
|
193
|
+
* not answerable per file; the answer is that the overlay never decides it;
|
|
194
|
+
* - a listed correction is PATCHED into the library's own definition: the
|
|
195
|
+
* named input fields and sidecar keys are added when absent, and nothing
|
|
196
|
+
* else is touched. It cannot change the operation's object or endpoint, so
|
|
197
|
+
* index row and entry file cannot be made to disagree. When the published
|
|
198
|
+
* definition already has everything, the correction is reported as no
|
|
199
|
+
* longer needed so its row can be removed;
|
|
200
|
+
* - an entry the library indexes at a DIFFERENT path is not copied: the copy
|
|
201
|
+
* would be a file no index row points at, which `--check-orphans` (the
|
|
202
|
+
* image build passes it) rejects, and stamping the flat curated file over
|
|
203
|
+
* each per-object variant the library serves would destroy their schemas.
|
|
204
|
+
* A correction in that position is warned about, since it no longer takes
|
|
205
|
+
* effect;
|
|
206
|
+
* - the SDK's side-tables (`list-envelopes.json`, `invariant-collections.json`)
|
|
207
|
+
* are the SDK's own data and are always copied.
|
|
56
208
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* here, because ONE event identity maps to MANY per-object paths in a
|
|
62
|
-
* refreshed library, and stamping the flat curated definition over each
|
|
63
|
-
* per-object variant would destroy the per-object schema the library just
|
|
64
|
-
* served — a worse regression than the one being fixed;
|
|
65
|
-
* - so the copy is skipped and said out loud. The library keeps the
|
|
66
|
-
* definition it resolves, the tree gains no unreachable file, and the
|
|
67
|
-
* operator is told which overlay row has been overtaken and needs
|
|
68
|
-
* re-verifying. The image build is then green before AND after a refresh.
|
|
209
|
+
* What was done is reported in one line, and recorded in `.curated-overlay.json`
|
|
210
|
+
* beside the index, so a second application recognises its own patches: the
|
|
211
|
+
* record keeps a sha256 of each patched entry and sidecar, and a correction
|
|
212
|
+
* whose files no longer match it is patched again.
|
|
69
213
|
*/
|
|
70
214
|
export async function applyCuratedOverlay(libraryPath, overlayPath = bundledOverlayPath(),
|
|
71
215
|
// The public materializer API does not forward one, and a warning nobody
|
|
@@ -74,6 +218,14 @@ reporter = consoleReporter) {
|
|
|
74
218
|
const indexPath = join(libraryPath, "index.json");
|
|
75
219
|
const destination = JSON.parse(await readFile(indexPath, "utf8"));
|
|
76
220
|
const overlay = JSON.parse(await readFile(join(overlayPath, "index.json"), "utf8"));
|
|
221
|
+
const corrections = new Map((await readOverlayCorrections(overlayPath)).map((correction) => [correction.path, correction]));
|
|
222
|
+
const recordPath = join(libraryPath, RECORD_FILE);
|
|
223
|
+
const previous = (await exists(recordPath))
|
|
224
|
+
? (await readJson(recordPath))
|
|
225
|
+
: {};
|
|
226
|
+
const previouslyAdded = new Set(previous.added ?? []);
|
|
227
|
+
const previousDigests = previous.correctedSha256 ?? {};
|
|
228
|
+
const digests = {};
|
|
77
229
|
const entries = destination.entries ?? [];
|
|
78
230
|
// Every path the library resolves each identity to. A `GenericExpanded` or
|
|
79
231
|
// per-object entry shares its nodeType with its siblings, so an identity
|
|
@@ -91,46 +243,110 @@ reporter = consoleReporter) {
|
|
|
91
243
|
}
|
|
92
244
|
const additions = [];
|
|
93
245
|
const skipped = new Set();
|
|
246
|
+
const added = [];
|
|
247
|
+
const corrected = [];
|
|
248
|
+
const kept = [];
|
|
249
|
+
const toCopy = new Set();
|
|
250
|
+
// Every entry file and sidecar the overlay's index accounts for; anything
|
|
251
|
+
// else in the directory is a side-table or the corrections ledger.
|
|
252
|
+
const rowFiles = new Set();
|
|
253
|
+
let written = 0;
|
|
94
254
|
for (const row of overlay.entries ?? []) {
|
|
255
|
+
if (typeof row.path !== "string")
|
|
256
|
+
continue;
|
|
257
|
+
rowFiles.add(row.path);
|
|
258
|
+
rowFiles.add(sidecarOf(row.path));
|
|
95
259
|
const identity = entryIdentity(row);
|
|
96
|
-
|
|
260
|
+
const correction = corrections.get(row.path);
|
|
261
|
+
const paths = resolvedPaths.get(identity);
|
|
262
|
+
if (paths === undefined) {
|
|
97
263
|
additions.push(row);
|
|
264
|
+
added.push(row.path);
|
|
265
|
+
toCopy.add(row.path);
|
|
266
|
+
toCopy.add(sidecarOf(row.path));
|
|
98
267
|
continue;
|
|
99
268
|
}
|
|
100
|
-
|
|
101
|
-
|
|
269
|
+
if (!paths.includes(row.path)) {
|
|
270
|
+
skipped.add(row.path);
|
|
271
|
+
if (correction) {
|
|
272
|
+
reporter.warn([
|
|
273
|
+
` WARN: curated overlay correction NOT applied: ${row.path} (${correction.since})`,
|
|
274
|
+
` ${String(row.nodeType)}@${String(row.version)} is in the library's index at`,
|
|
275
|
+
...paths.map((path) => ` ${path}`),
|
|
276
|
+
" instead, so the library's own definition stands without this correction.",
|
|
277
|
+
` Re-verify it there and update ${CORRECTIONS_FILE}.`,
|
|
278
|
+
].join("\n"));
|
|
279
|
+
}
|
|
102
280
|
continue;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
281
|
+
}
|
|
282
|
+
if (!correction) {
|
|
283
|
+
// A row this overlay added on an earlier application is still its own.
|
|
284
|
+
(previouslyAdded.has(row.path) ? added : kept).push(row.path);
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
// Our own earlier patch, as long as neither file changed since: a refreshed
|
|
288
|
+
// entry (an `unzip -o` over the same directory, say) is patched again.
|
|
289
|
+
const digest = await correctionDigest(libraryPath, row.path);
|
|
290
|
+
if (previousDigests[row.path] === digest) {
|
|
291
|
+
corrected.push(row.path);
|
|
292
|
+
digests[row.path] = digest;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
const patched = await patchCorrection(libraryPath, overlayPath, correction);
|
|
296
|
+
if (patched.added.length === 0) {
|
|
297
|
+
kept.push(row.path);
|
|
298
|
+
reporter.warn([
|
|
299
|
+
` WARN: curated overlay correction no longer needed: ${row.path} (${correction.since})`,
|
|
300
|
+
" The published definition already carries every field and key it adds.",
|
|
301
|
+
` Remove its row from typescript/sdk/lib/library-json.samples/${CORRECTIONS_FILE}.`,
|
|
302
|
+
].join("\n"));
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
corrected.push(row.path);
|
|
306
|
+
digests[row.path] = await correctionDigest(libraryPath, row.path);
|
|
307
|
+
written += patched.files;
|
|
119
308
|
}
|
|
120
309
|
const overlayFiles = await jsonFiles(overlayPath);
|
|
121
|
-
let copied = 0;
|
|
122
310
|
for (const source of overlayFiles) {
|
|
123
311
|
const rel = relative(overlayPath, source).split(sep).join("/");
|
|
124
|
-
if (
|
|
312
|
+
if (rel === "index.json" || rel === CORRECTIONS_FILE)
|
|
313
|
+
continue;
|
|
314
|
+
const accounted = rowFiles.has(rel);
|
|
315
|
+
// An entry or sidecar goes only where its row decided; a side-table always;
|
|
316
|
+
// any other file only into a library that lacks it, so a stray file here
|
|
317
|
+
// can never replace a published one either.
|
|
318
|
+
if (accounted && !toCopy.has(rel))
|
|
319
|
+
continue;
|
|
320
|
+
if (!accounted && !SIDE_TABLES.has(rel) && (await exists(join(libraryPath, rel))))
|
|
125
321
|
continue;
|
|
126
322
|
const target = join(libraryPath, rel);
|
|
127
323
|
await mkdir(dirname(target), { recursive: true });
|
|
128
324
|
await cp(source, target);
|
|
129
|
-
|
|
325
|
+
written += 1;
|
|
130
326
|
}
|
|
131
327
|
if (additions.length > 0) {
|
|
132
328
|
destination.entries = [...entries, ...additions];
|
|
133
329
|
writeJsonFile(indexPath, destination);
|
|
134
330
|
}
|
|
135
|
-
|
|
331
|
+
const result = {
|
|
332
|
+
files: written,
|
|
333
|
+
entries: additions.length,
|
|
334
|
+
skipped: sortedStrings([...skipped]),
|
|
335
|
+
added: sortedStrings(added),
|
|
336
|
+
corrected: sortedStrings(corrected),
|
|
337
|
+
kept: sortedStrings(kept),
|
|
338
|
+
};
|
|
339
|
+
writeJsonFile(recordPath, {
|
|
340
|
+
$comment: "What the SDK's curated overlay did to this library (registry pull). See curated-overlay.ts.",
|
|
341
|
+
added: result.added,
|
|
342
|
+
corrected: result.corrected,
|
|
343
|
+
correctedSha256: digests,
|
|
344
|
+
kept: result.kept,
|
|
345
|
+
skipped: result.skipped,
|
|
346
|
+
});
|
|
347
|
+
reporter.info(`curated overlay: added ${result.added.length} definition(s) the library lacks, ` +
|
|
348
|
+
`corrected ${result.corrected.length}` +
|
|
349
|
+
(result.corrected.length ? ` (${result.corrected.join(", ")})` : "") +
|
|
350
|
+
`, kept ${result.kept.length + result.skipped.length} published definition(s) unchanged.`);
|
|
351
|
+
return result;
|
|
136
352
|
}
|
package/dist/registry/orphans.js
CHANGED
|
@@ -35,10 +35,12 @@ import { sortedStrings } from "./compat/compare.js";
|
|
|
35
35
|
* `list-envelopes.json` is the LIST-ENVELOPE LEDGER (a side-table keyed by
|
|
36
36
|
* nodeType, flow-builder-sdk#156); `invariant-collections.json` is the second
|
|
37
37
|
* such side-table, keyed by a reference's `objectName` instead
|
|
38
|
-
* (CONNECTOR_LOOKUP_DESIGN.md §5.3).
|
|
39
|
-
*
|
|
38
|
+
* (CONNECTOR_LOOKUP_DESIGN.md §5.3). `overlay-corrections.json` is the
|
|
39
|
+
* curated overlay's ledger of deliberate patches (#1148); the overlay never
|
|
40
|
+
* copies it, but a test library copied from the samples carries it. Asking any
|
|
41
|
+
* of them for an index row is the wrong question. Dotfiles are excluded separately — see {@link isDotfile}.
|
|
40
42
|
*/
|
|
41
|
-
const SIDE_TABLES = new Set(["index.json", "list-envelopes.json", "invariant-collections.json"]);
|
|
43
|
+
const SIDE_TABLES = new Set(["index.json", "list-envelopes.json", "invariant-collections.json", "overlay-corrections.json"]);
|
|
42
44
|
/**
|
|
43
45
|
* A dotfile is never an operation entry, so it can never have an index row.
|
|
44
46
|
*
|
package/dist/serialize.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import ixpDefinition from './ixp-definition.json' with { type: 'json' };
|
|
10
10
|
import { BUNDLED_DEFINITIONS, bundledVersions } from './flow-definitions.js';
|
|
11
|
+
import { LOOP_DEFAULT_VERSION, bodyUsesBreak, loopHasInnerHandles, loopVersion, loopVersionRefusal } from './loop-version.js';
|
|
11
12
|
import { Expr, toExpr, SCHEDULE_PRESETS, parseIxpProjectType, flatNameOf, flatNameSegmentsOf } from './flow-sdk.js';
|
|
12
13
|
import { FlowAction, FlowTrigger } from './core/node-classes.js';
|
|
13
14
|
import { CONTEXT_INDEX_DEFAULTS, CONTEXT_INDEX_DEFAULT_FILE_EXTENSION, contextIndexType } from './core/context-index.js';
|
|
@@ -75,15 +76,6 @@ const defByType = new Map();
|
|
|
75
76
|
for (const d of Object.values(DEFS))
|
|
76
77
|
if (!defByType.has(d.nodeType))
|
|
77
78
|
defByType.set(d.nodeType, d);
|
|
78
|
-
/** True when a container body (or an arm/handler inside it, but not a NESTED container's body) breaks. */
|
|
79
|
-
function bodyUsesBreak(steps) {
|
|
80
|
-
return steps.some((s) => s.kind === 'break'
|
|
81
|
-
|| (s.kind === 'branch' && (bodyUsesBreak(s.then) || bodyUsesBreak(s.otherwise)))
|
|
82
|
-
|| (s.kind === 'switch' && (s.cases.some((c) => bodyUsesBreak(c.body)) || (s.default ? bodyUsesBreak(s.default) : false)))
|
|
83
|
-
|| (s.kind === 'stepSwitch' && s.cases.some((c) => bodyUsesBreak(c.body)))
|
|
84
|
-
|| (s.kind === 'parallel' && s.arms.some(bodyUsesBreak))
|
|
85
|
-
|| (s.kind === 'stepToList' && bodyUsesBreak(s.body)));
|
|
86
|
-
}
|
|
87
79
|
const NODE_TYPE = {
|
|
88
80
|
trigger: 'core.trigger.manual',
|
|
89
81
|
scheduledTrigger: 'core.trigger.scheduled',
|
|
@@ -3448,8 +3440,6 @@ export function actionVersion(spec, explicit) {
|
|
|
3448
3440
|
export function bundledDefinition(nodeType, requestedVersion) {
|
|
3449
3441
|
return requestedVersion !== undefined ? DEFS[`${nodeType}@${requestedVersion}`] : defByType.get(nodeType);
|
|
3450
3442
|
}
|
|
3451
|
-
/** The `core.logic.loop` version `.loop()` emits unless `{ version }` pins another. */
|
|
3452
|
-
const LOOP_DEFAULT_VERSION = '2.4';
|
|
3453
3443
|
/**
|
|
3454
3444
|
* The bundled definition a `.loop()` or `.doWhile()` container emits, at the
|
|
3455
3445
|
* version serialize writes (`.loop()` defaults to `@2.4`, `.doWhile()` to the
|
|
@@ -6342,15 +6332,14 @@ export function serialize(built, opts = {}) {
|
|
|
6342
6332
|
// designer authors (inner start/continue/break handles, `currentIteration`
|
|
6343
6333
|
// output). 1.0.0 is the legacy shape the canvas shows in its old form; it
|
|
6344
6334
|
// is emitted only when { version: '1.0.0' } is pinned explicitly (#868).
|
|
6345
|
-
// An
|
|
6346
|
-
// resolve, not a silent drop
|
|
6347
|
-
|
|
6348
|
-
const
|
|
6349
|
-
if (
|
|
6350
|
-
throw new Error(
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
const v24 = version !== '1.0.0';
|
|
6335
|
+
// An option or a .break() the pinned version's definition cannot express
|
|
6336
|
+
// is a contradiction the author must resolve, not a silent drop; `check`
|
|
6337
|
+
// reports the same refusal from the same helper (#1186).
|
|
6338
|
+
const refusal = loopVersionRefusal(step.name, o, usesBreak);
|
|
6339
|
+
if (refusal)
|
|
6340
|
+
throw new Error(refusal);
|
|
6341
|
+
const version = loopVersion(o);
|
|
6342
|
+
const v24 = loopHasInnerHandles(version);
|
|
6354
6343
|
const id = stepUid(scope, step.name);
|
|
6355
6344
|
const node = makeNode(NODE_TYPE.loop, id, step.options?.label ?? step.label ?? step.name, { parentId, requestedVersion: version });
|
|
6356
6345
|
node.inputs = v24
|
|
@@ -6362,7 +6351,7 @@ export function serialize(built, opts = {}) {
|
|
|
6362
6351
|
: {}),
|
|
6363
6352
|
breakEnabled: (o.breakEnabled ?? false) || usesBreak,
|
|
6364
6353
|
}
|
|
6365
|
-
: { collection: renderValue(step.collection, scope.rename), parallel: false };
|
|
6354
|
+
: { collection: renderValue(step.collection, scope.rename), parallel: o.parallel ?? false };
|
|
6366
6355
|
scope.nodes.push(node);
|
|
6367
6356
|
for (const t of tails)
|
|
6368
6357
|
addEdge(scope, t, id);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1",
|
|
3
|
+
"$comment": [
|
|
4
|
+
"THE CORRECTIONS LEDGER: which files in this directory deliberately patch a published definition.",
|
|
5
|
+
"",
|
|
6
|
+
"This directory has two jobs. It is the small connector library the tests and the examples read,",
|
|
7
|
+
"and it is the curated overlay `registry pull` applies to a freshly downloaded library. Only the",
|
|
8
|
+
"second job can damage a user's library, and only through the rows listed here.",
|
|
9
|
+
"",
|
|
10
|
+
"THE RULE (`src/registry/curated-overlay.ts`). An overlay entry whose (nodeType, version) the",
|
|
11
|
+
"downloaded library does NOT carry is added, with its index row. An entry the library DOES carry is",
|
|
12
|
+
"left alone: the published definition wins, because a copy here is a snapshot that goes stale the",
|
|
13
|
+
"day the library is republished (builder-sdk#1148: nine 2026-07 snapshots were replacing newer",
|
|
14
|
+
"published definitions, Outlook `send-email` among them). The one exception is a row in",
|
|
15
|
+
"`corrections` below, and a correction is a PATCH, never a replacement: it adds the named input",
|
|
16
|
+
"fields and sidecar keys the published definition lacks, taking them from this directory's copy,",
|
|
17
|
+
"and touches nothing else. It cannot change `operation.objectName` or the endpoint, so the index",
|
|
18
|
+
"row and the entry file keep agreeing.",
|
|
19
|
+
"",
|
|
20
|
+
"A correction the published library has caught up with (it already has every field and key) is",
|
|
21
|
+
"reported as no longer needed. Remove its row here once a published build carries it.",
|
|
22
|
+
"",
|
|
23
|
+
"FIELDS. `path`: the entry file, as in index.json. `since`: the change that made it. `reason`:",
|
|
24
|
+
"why the published definition is wrong. `inputFields`: names added to `inputSchema.fields` (entry)",
|
|
25
|
+
"and `inputDefinition.fields` (sidecar) when absent. `sidecarKeys`: top-level sidecar keys added",
|
|
26
|
+
"when absent."
|
|
27
|
+
],
|
|
28
|
+
"corrections": [
|
|
29
|
+
{
|
|
30
|
+
"path": "uipath-atlassian-jira/create-issue@1.0.0.json",
|
|
31
|
+
"since": "builder-sdk#108",
|
|
32
|
+
"reason": "Jira refuses a create without fields.summary (400). The published definition leaves the body fields to design-time schema generation, so a flow authored without `registry prepare` could not set summary or description, and nothing typed the created issue's key.",
|
|
33
|
+
"inputFields": [
|
|
34
|
+
"fields.summary",
|
|
35
|
+
"fields.description",
|
|
36
|
+
"key"
|
|
37
|
+
],
|
|
38
|
+
"sidecarKeys": [
|
|
39
|
+
"outputResponseDefinition"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -10,23 +10,66 @@
|
|
|
10
10
|
],
|
|
11
11
|
"connector": {
|
|
12
12
|
"key": "uipath-microsoft-outlook365",
|
|
13
|
-
"name": "Microsoft Outlook 365"
|
|
13
|
+
"name": "Microsoft Outlook 365",
|
|
14
|
+
"tier": "1",
|
|
15
|
+
"discovery": {
|
|
16
|
+
"type": "static",
|
|
17
|
+
"hasObjectDiscovery": false,
|
|
18
|
+
"hasFieldDiscovery": false,
|
|
19
|
+
"hasCustomObjectDiscovery": false,
|
|
20
|
+
"hasCustomFieldDiscovery": false
|
|
21
|
+
}
|
|
14
22
|
},
|
|
15
23
|
"operation": {
|
|
16
24
|
"name": "Create",
|
|
17
|
-
"objectName": "send-mail",
|
|
25
|
+
"objectName": "send-mail-v2",
|
|
18
26
|
"objectDisplayName": "Send Email",
|
|
19
27
|
"httpMethod": "POST",
|
|
20
|
-
"path": "/hubs/productivity/send-mail",
|
|
28
|
+
"path": "/hubs/productivity/send-mail-v2",
|
|
21
29
|
"subType": "standard",
|
|
22
30
|
"supportsStreaming": false,
|
|
23
31
|
"activityType": "Curated",
|
|
24
|
-
"pathTemplate": "/hubs/productivity/send-mail",
|
|
25
|
-
"parameters": [
|
|
32
|
+
"pathTemplate": "/hubs/productivity/send-mail-v2",
|
|
33
|
+
"parameters": [
|
|
34
|
+
{
|
|
35
|
+
"name": "saveAsDraft",
|
|
36
|
+
"type": "query",
|
|
37
|
+
"dataType": "boolean",
|
|
38
|
+
"required": false,
|
|
39
|
+
"displayName": "Save as draft",
|
|
40
|
+
"description": "Send an email message. By default, the email will be saved as draft.",
|
|
41
|
+
"defaultValue": true
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "includeMessageDetails",
|
|
45
|
+
"type": "query",
|
|
46
|
+
"dataType": "boolean",
|
|
47
|
+
"required": false,
|
|
48
|
+
"displayName": "Include message details",
|
|
49
|
+
"description": "Returns the sent message's identifiers (message ID, conversation ID, internet message ID, status) when set to true. If set to false, response only contains status.",
|
|
50
|
+
"defaultValue": false
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "file",
|
|
54
|
+
"type": "multipart",
|
|
55
|
+
"dataType": "file",
|
|
56
|
+
"required": false,
|
|
57
|
+
"displayName": "Attachment",
|
|
58
|
+
"description": "The file to attach to the email"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "body",
|
|
62
|
+
"type": "multipart",
|
|
63
|
+
"dataType": "string",
|
|
64
|
+
"required": false,
|
|
65
|
+
"displayName": "Body",
|
|
66
|
+
"description": "The object body"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
26
69
|
},
|
|
27
70
|
"display": {
|
|
28
71
|
"label": "Send Email",
|
|
29
|
-
"description": "
|
|
72
|
+
"description": "Send an email message based on the input parameters",
|
|
30
73
|
"icon": "https://alpha.uipath.com/311c6049-4966-4ef2-a6f3-8ceccaf38d54/studio_/typecache/icons/160499b52f7cea190b530fe6f40da7ee03455a8d3fb72dd7f4f68d61e7865a3a.svg",
|
|
31
74
|
"iconBackground": "",
|
|
32
75
|
"iconBackgroundDark": "",
|