@uipath/maestro-builder-sdk 6.54.0 → 6.54.1

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.
@@ -78,6 +78,30 @@ export declare function readOverlayCorrections(overlayPath: string): Promise<Ove
78
78
  * What was done is reported in one line, and recorded in `.curated-overlay.json`
79
79
  * beside the index, so a second application recognises its own patches: the
80
80
  * record keeps a sha256 of each patched entry and sidecar, and a correction
81
- * whose files no longer match it is patched again.
81
+ * whose files no longer match it is patched again. The record also names the
82
+ * overlay that wrote it ({@link curatedOverlayIdentity}). Under a different
83
+ * overlay, such as a newer SDK pulling a published archive, every correction
84
+ * is patched again, so fields a newer correction lists are added.
82
85
  */
83
86
  export declare function applyCuratedOverlay(libraryPath: string, overlayPath?: string, reporter?: Reporter): Promise<CuratedOverlayResult>;
87
+ /** What {@link checkCuratedOverlay} found, one line per item. */
88
+ export interface CuratedOverlayCheck {
89
+ /** Parts the overlay adds that are absent: the overlay was not applied, or broke. */
90
+ missing: string[];
91
+ /**
92
+ * Corrections whose target the library no longer serves at the correction's
93
+ * path, or serves without the fields the patch adds: the operation moved,
94
+ * was renamed or re-versioned. `registry pull` only warns about these too.
95
+ */
96
+ staleCorrections: string[];
97
+ }
98
+ /**
99
+ * Check `libraryPath` against the curated overlay. Both lists are empty once
100
+ * {@link applyCuratedOverlay} has run on it, unless a correction went stale.
101
+ * Every overlay identity that is not a correction must be indexed at a file
102
+ * that exists, and each side-table must equal the bundled copy.
103
+ *
104
+ * The connector library pipeline runs this on the archive it publishes,
105
+ * because readers that load that archive directly apply no overlay.
106
+ */
107
+ export declare function checkCuratedOverlay(libraryPath: string, overlayPath?: string): Promise<CuratedOverlayCheck>;
@@ -34,6 +34,25 @@ export async function curatedOverlayIdentity(overlayPath = bundledOverlayPath())
34
34
  function entryIdentity(entry) {
35
35
  return `${String(entry.nodeType)}\0${String(entry.version)}`;
36
36
  }
37
+ /**
38
+ * Every path the library resolves each identity to. A `GenericExpanded` or
39
+ * per-object entry shares its nodeType with its siblings, so an identity
40
+ * legitimately has more than one.
41
+ */
42
+ function pathsByIdentity(entries) {
43
+ const resolvedPaths = new Map();
44
+ for (const entry of entries) {
45
+ if (typeof entry.path !== "string")
46
+ continue;
47
+ const identity = entryIdentity(entry);
48
+ const known = resolvedPaths.get(identity);
49
+ if (known === undefined)
50
+ resolvedPaths.set(identity, [entry.path]);
51
+ else
52
+ known.push(entry.path);
53
+ }
54
+ return resolvedPaths;
55
+ }
37
56
  /** The ledger of deliberate patches; read here, never copied into a library. */
38
57
  export const CORRECTIONS_FILE = "overlay-corrections.json";
39
58
  /**
@@ -209,7 +228,10 @@ async function patchCorrection(libraryPath, overlayPath, correction) {
209
228
  * What was done is reported in one line, and recorded in `.curated-overlay.json`
210
229
  * beside the index, so a second application recognises its own patches: the
211
230
  * record keeps a sha256 of each patched entry and sidecar, and a correction
212
- * whose files no longer match it is patched again.
231
+ * whose files no longer match it is patched again. The record also names the
232
+ * overlay that wrote it ({@link curatedOverlayIdentity}). Under a different
233
+ * overlay, such as a newer SDK pulling a published archive, every correction
234
+ * is patched again, so fields a newer correction lists are added.
213
235
  */
214
236
  export async function applyCuratedOverlay(libraryPath, overlayPath = bundledOverlayPath(),
215
237
  // The public materializer API does not forward one, and a warning nobody
@@ -223,24 +245,13 @@ reporter = consoleReporter) {
223
245
  const previous = (await exists(recordPath))
224
246
  ? (await readJson(recordPath))
225
247
  : {};
248
+ const overlayIdentity = await curatedOverlayIdentity(overlayPath);
249
+ const sameOverlay = previous.overlayIdentity === overlayIdentity;
226
250
  const previouslyAdded = new Set(previous.added ?? []);
227
251
  const previousDigests = previous.correctedSha256 ?? {};
228
252
  const digests = {};
229
253
  const entries = destination.entries ?? [];
230
- // Every path the library resolves each identity to. A `GenericExpanded` or
231
- // per-object entry shares its nodeType with its siblings, so an identity
232
- // legitimately has more than one.
233
- const resolvedPaths = new Map();
234
- for (const entry of entries) {
235
- if (typeof entry.path !== "string")
236
- continue;
237
- const identity = entryIdentity(entry);
238
- const known = resolvedPaths.get(identity);
239
- if (known === undefined)
240
- resolvedPaths.set(identity, [entry.path]);
241
- else
242
- known.push(entry.path);
243
- }
254
+ const resolvedPaths = pathsByIdentity(entries);
244
255
  const additions = [];
245
256
  const skipped = new Set();
246
257
  const added = [];
@@ -285,15 +296,18 @@ reporter = consoleReporter) {
285
296
  continue;
286
297
  }
287
298
  // 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.
299
+ // entry (an `unzip -o` over the same directory, say) is patched again. So
300
+ // is our patch under another overlay, whose correction may list more; when
301
+ // it lists nothing new, the patch is still ours, not upstream catching up.
289
302
  const digest = await correctionDigest(libraryPath, row.path);
290
- if (previousDigests[row.path] === digest) {
303
+ const ownPatch = previousDigests[row.path] === digest;
304
+ if (ownPatch && sameOverlay) {
291
305
  corrected.push(row.path);
292
306
  digests[row.path] = digest;
293
307
  continue;
294
308
  }
295
309
  const patched = await patchCorrection(libraryPath, overlayPath, correction);
296
- if (patched.added.length === 0) {
310
+ if (patched.added.length === 0 && !ownPatch) {
297
311
  kept.push(row.path);
298
312
  reporter.warn([
299
313
  ` WARN: curated overlay correction no longer needed: ${row.path} (${correction.since})`,
@@ -338,6 +352,7 @@ reporter = consoleReporter) {
338
352
  };
339
353
  writeJsonFile(recordPath, {
340
354
  $comment: "What the SDK's curated overlay did to this library (registry pull). See curated-overlay.ts.",
355
+ overlayIdentity,
341
356
  added: result.added,
342
357
  corrected: result.corrected,
343
358
  correctedSha256: digests,
@@ -350,3 +365,82 @@ reporter = consoleReporter) {
350
365
  `, kept ${result.kept.length + result.skipped.length} published definition(s) unchanged.`);
351
366
  return result;
352
367
  }
368
+ /**
369
+ * Check `libraryPath` against the curated overlay. Both lists are empty once
370
+ * {@link applyCuratedOverlay} has run on it, unless a correction went stale.
371
+ * Every overlay identity that is not a correction must be indexed at a file
372
+ * that exists, and each side-table must equal the bundled copy.
373
+ *
374
+ * The connector library pipeline runs this on the archive it publishes,
375
+ * because readers that load that archive directly apply no overlay.
376
+ */
377
+ export async function checkCuratedOverlay(libraryPath, overlayPath = bundledOverlayPath()) {
378
+ const library = (await readJson(join(libraryPath, "index.json")));
379
+ const overlay = (await readJson(join(overlayPath, "index.json")));
380
+ const corrections = await readOverlayCorrections(overlayPath);
381
+ const correctionPaths = new Set(corrections.map((correction) => correction.path));
382
+ const resolvedPaths = pathsByIdentity(library.entries ?? []);
383
+ const overlayRows = new Map();
384
+ const missing = [];
385
+ const staleCorrections = [];
386
+ for (const row of overlay.entries ?? []) {
387
+ if (typeof row.path !== "string")
388
+ continue;
389
+ overlayRows.set(row.path, row);
390
+ if (correctionPaths.has(row.path))
391
+ continue;
392
+ const name = `${String(row.nodeType)}@${String(row.version)}`;
393
+ const paths = resolvedPaths.get(entryIdentity(row));
394
+ if (paths === undefined) {
395
+ missing.push(`definition ${name}: no index row`);
396
+ continue;
397
+ }
398
+ for (const path of paths) {
399
+ if (!(await exists(join(libraryPath, path))))
400
+ missing.push(`definition ${name}: indexed at ${path}, which is absent`);
401
+ }
402
+ }
403
+ for (const correction of corrections) {
404
+ const where = `correction ${correction.path} (${correction.since})`;
405
+ const paths = resolvedPaths.get(entryIdentity(overlayRows.get(correction.path))) ?? [];
406
+ if (!paths.includes(correction.path)) {
407
+ staleCorrections.push(`${where}: the library has no definition at that path${paths.length ? ` (it indexes ${paths.join(", ")})` : ""}`);
408
+ continue;
409
+ }
410
+ if (!(await exists(join(libraryPath, correction.path)))) {
411
+ staleCorrections.push(`${where}: the library indexes that path, but the file is absent`);
412
+ continue;
413
+ }
414
+ const lacks = [];
415
+ const entry = (await readJson(join(libraryPath, correction.path)));
416
+ const entryFields = fieldNames(entry.inputSchema?.fields);
417
+ for (const field of correction.inputFields ?? []) {
418
+ if (!entryFields.has(field))
419
+ lacks.push(`inputSchema field ${field}`);
420
+ }
421
+ const sidecarPath = join(libraryPath, sidecarOf(correction.path));
422
+ if (await exists(sidecarPath)) {
423
+ const sidecar = sidecarBody(await readJson(sidecarPath)) ?? {};
424
+ const sidecarFields = fieldNames(sidecar.inputDefinition?.fields);
425
+ for (const field of correction.inputFields ?? []) {
426
+ if (!sidecarFields.has(field))
427
+ lacks.push(`sidecar inputDefinition field ${field}`);
428
+ }
429
+ for (const key of correction.sidecarKeys ?? []) {
430
+ if (!(key in sidecar))
431
+ lacks.push(`sidecar key ${key}`);
432
+ }
433
+ }
434
+ if (lacks.length > 0)
435
+ staleCorrections.push(`${where}: the definition lacks ${lacks.join(", ")}`);
436
+ }
437
+ for (const table of SIDE_TABLES) {
438
+ const target = join(libraryPath, table);
439
+ if (!(await exists(target)))
440
+ missing.push(`side-table ${table}: absent`);
441
+ else if (!(await readFile(target)).equals(await readFile(join(overlayPath, table)))) {
442
+ missing.push(`side-table ${table}: differs from the SDK's copy`);
443
+ }
444
+ }
445
+ return { missing, staleCorrections };
446
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.54.0",
3
+ "version": "6.54.1",
4
4
  "description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.uipath.com/maestro",
@@ -96,5 +96,5 @@
96
96
  "@types/node": "^22.7.0",
97
97
  "esbuild": "^0.28.1"
98
98
  },
99
- "gitref": "f215db445a4e5067bdf31b92c72604c121b52e9e"
99
+ "gitref": "5dfee12e621c69cfa2cf1338fc7df299768dbe16"
100
100
  }