@uipath/maestro-builder-sdk 6.4.0 → 6.5.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.
- package/dist/bpmn/uipath-moddle.v1.json +21 -0
- package/dist/cli/commands/registry.js +68 -12
- package/dist/registry/archive/entry-policy.d.ts +36 -0
- package/dist/registry/archive/entry-policy.js +60 -0
- package/dist/registry/archive/extract.d.ts +31 -0
- package/dist/registry/archive/extract.js +92 -0
- package/dist/registry/archive/zip-reader.d.ts +38 -0
- package/dist/registry/archive/zip-reader.js +256 -0
- package/dist/registry/codecs/pyjson.d.ts +62 -0
- package/dist/registry/codecs/pyjson.js +208 -0
- package/dist/registry/compat/compare.d.ts +18 -0
- package/dist/registry/compat/compare.js +32 -0
- package/dist/registry/compat/paths.d.ts +4 -0
- package/dist/registry/compat/paths.js +17 -0
- package/dist/registry/compat/pystr.d.ts +50 -0
- package/dist/registry/compat/pystr.js +221 -0
- package/dist/registry/concurrency.d.ts +10 -0
- package/dist/registry/concurrency.js +34 -0
- package/dist/registry/curated-overlay.d.ts +36 -4
- package/dist/registry/curated-overlay.js +87 -14
- package/dist/registry/errors.d.ts +26 -0
- package/dist/registry/errors.js +38 -0
- package/dist/registry/extractor.d.ts +9 -10
- package/dist/registry/extractor.js +5 -15
- package/dist/registry/files.d.ts +26 -0
- package/dist/registry/files.js +160 -0
- package/dist/registry/generators/descriptors.d.ts +81 -0
- package/dist/registry/generators/descriptors.js +405 -0
- package/dist/registry/generators/fields.d.ts +46 -0
- package/dist/registry/generators/fields.js +111 -0
- package/dist/registry/generators/markdown/common.d.ts +21 -0
- package/dist/registry/generators/markdown/common.js +55 -0
- package/dist/registry/generators/markdown/index.d.ts +33 -0
- package/dist/registry/generators/markdown/index.js +37 -0
- package/dist/registry/generators/markdown/page.d.ts +8 -0
- package/dist/registry/generators/markdown/page.js +52 -0
- package/dist/registry/generators/markdown/pyvalue.d.ts +34 -0
- package/dist/registry/generators/markdown/pyvalue.js +106 -0
- package/dist/registry/generators/markdown/sections/choosing-object.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/choosing-object.js +52 -0
- package/dist/registry/generators/markdown/sections/example.d.ts +22 -0
- package/dist/registry/generators/markdown/sections/example.js +295 -0
- package/dist/registry/generators/markdown/sections/filtering.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/filtering.js +76 -0
- package/dist/registry/generators/markdown/sections/header.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/header.js +37 -0
- package/dist/registry/generators/markdown/sections/inputs.d.ts +30 -0
- package/dist/registry/generators/markdown/sections/inputs.js +151 -0
- package/dist/registry/generators/markdown/sections/lookups.d.ts +12 -0
- package/dist/registry/generators/markdown/sections/lookups.js +150 -0
- package/dist/registry/generators/markdown/sections/outputs.d.ts +3 -0
- package/dist/registry/generators/markdown/sections/outputs.js +9 -0
- package/dist/registry/generators/markdown/sections/resolving-fields.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/resolving-fields.js +139 -0
- package/dist/registry/generators/markdown/sections/schema-dynamic.d.ts +2 -0
- package/dist/registry/generators/markdown/sections/schema-dynamic.js +86 -0
- package/dist/registry/generators/materialize.d.ts +30 -0
- package/dist/registry/generators/materialize.js +132 -0
- package/dist/registry/generators/md-symbols.d.ts +22 -0
- package/dist/registry/generators/md-symbols.js +58 -0
- package/dist/registry/generators/triggers.d.ts +15 -0
- package/dist/registry/generators/triggers.js +85 -0
- package/dist/registry/generators/type-registry.d.ts +50 -0
- package/dist/registry/generators/type-registry.js +154 -0
- package/dist/registry/generators/type-tree.d.ts +65 -0
- package/dist/registry/generators/type-tree.js +179 -0
- package/dist/registry/library-build/build.d.ts +57 -0
- package/dist/registry/library-build/build.js +286 -0
- package/dist/registry/library-build/canonical.d.ts +119 -0
- package/dist/registry/library-build/canonical.js +512 -0
- package/dist/registry/library-build/cli.d.ts +45 -0
- package/dist/registry/library-build/cli.js +182 -0
- package/dist/registry/library-build/context.d.ts +107 -0
- package/dist/registry/library-build/context.js +267 -0
- package/dist/registry/library-build/enrich.d.ts +36 -0
- package/dist/registry/library-build/enrich.js +158 -0
- package/dist/registry/library-build/events.d.ts +108 -0
- package/dist/registry/library-build/events.js +476 -0
- package/dist/registry/library-build/generic-expand.d.ts +77 -0
- package/dist/registry/library-build/generic-expand.js +363 -0
- package/dist/registry/library-build/plan.d.ts +71 -0
- package/dist/registry/library-build/plan.js +270 -0
- package/dist/registry/library-build/py.d.ts +45 -0
- package/dist/registry/library-build/py.js +167 -0
- package/dist/registry/library-build/schema-action.d.ts +38 -0
- package/dist/registry/library-build/schema-action.js +107 -0
- package/dist/registry/library-build/write.d.ts +6 -0
- package/dist/registry/library-build/write.js +26 -0
- package/dist/registry/library-reader.d.ts +20 -0
- package/dist/registry/library-reader.js +50 -0
- package/dist/registry/lookup-specs.d.ts +55 -0
- package/dist/registry/lookup-specs.js +140 -0
- package/dist/registry/materialize-cli.js +28 -14
- package/dist/registry/materializer.d.ts +25 -3
- package/dist/registry/materializer.js +45 -29
- package/dist/registry/model/library.d.ts +254 -0
- package/dist/registry/model/library.js +23 -0
- package/dist/registry/naming.d.ts +54 -0
- package/dist/registry/naming.js +142 -0
- package/dist/registry/orphans.d.ts +4 -0
- package/dist/registry/orphans.js +86 -0
- package/dist/registry/prepare/actions.d.ts +26 -0
- package/dist/registry/prepare/actions.js +94 -0
- package/dist/registry/prepare/connections.d.ts +181 -0
- package/dist/registry/prepare/connections.js +399 -0
- package/dist/registry/prepare/event.d.ts +96 -0
- package/dist/registry/prepare/event.js +268 -0
- package/dist/registry/prepare/handoff.d.ts +21 -0
- package/dist/registry/prepare/handoff.js +91 -0
- package/dist/registry/prepare/ledger.d.ts +104 -0
- package/dist/registry/prepare/ledger.js +216 -0
- package/dist/registry/prepare/messages.d.ts +190 -0
- package/dist/registry/prepare/messages.js +472 -0
- package/dist/registry/prepare/objects.d.ts +130 -0
- package/dist/registry/prepare/objects.js +318 -0
- package/dist/registry/prepare/overlay.d.ts +149 -0
- package/dist/registry/prepare/overlay.js +487 -0
- package/dist/registry/prepare/parents.d.ts +41 -0
- package/dist/registry/prepare/parents.js +122 -0
- package/dist/registry/prepare/pipeline.d.ts +91 -0
- package/dist/registry/prepare/pipeline.js +376 -0
- package/dist/registry/prepare/regenerate.d.ts +9 -0
- package/dist/registry/prepare/regenerate.js +50 -0
- package/dist/registry/prepare/resolve.d.ts +199 -0
- package/dist/registry/prepare/resolve.js +470 -0
- package/dist/registry/prepare/retry.d.ts +83 -0
- package/dist/registry/prepare/retry.js +109 -0
- package/dist/registry/prepare/source-import.d.ts +54 -0
- package/dist/registry/prepare/source-import.js +192 -0
- package/dist/registry/prepare/support.d.ts +41 -0
- package/dist/registry/prepare/support.js +178 -0
- package/dist/registry/prepare-cli.d.ts +16 -5
- package/dist/registry/prepare-cli.js +60 -53
- package/dist/registry/pull-cli.js +8 -7
- package/dist/registry/reporter.d.ts +26 -0
- package/dist/registry/reporter.js +41 -0
- package/dist/registry/uip/client.d.ts +99 -0
- package/dist/registry/uip/client.js +226 -0
- package/dist/registry/uip/commands.d.ts +40 -0
- package/dist/registry/uip/commands.js +80 -0
- package/dist/registry/uip/envelope.d.ts +37 -0
- package/dist/registry/uip/envelope.js +84 -0
- package/dist/registry/uip/response-cache.d.ts +28 -0
- package/dist/registry/uip/response-cache.js +57 -0
- package/lib/README.md +10 -8
- package/package.json +3 -3
- package/dist/generators/_connections.py +0 -331
- package/dist/generators/_events.py +0 -355
- package/dist/generators/_lookups.py +0 -114
- package/dist/generators/_naming.py +0 -185
- package/dist/generators/_objects.py +0 -299
- package/dist/generators/_resolve.py +0 -319
- package/dist/generators/convert_library_to_md.py +0 -1441
- package/dist/generators/extract_library.py +0 -125
- package/dist/generators/generate_connectors_ts.py +0 -936
- package/dist/generators/generate_library_json.py +0 -2527
- package/dist/generators/generate_triggers_ts.py +0 -110
- package/dist/generators/materialize_registry.py +0 -155
- package/dist/generators/prepare_connector.py +0 -1860
- package/dist/registry/python.d.ts +0 -26
- package/dist/registry/python.js +0 -46
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `registry build-library`: the Azure pipeline's library generator as a verb.
|
|
3
|
+
*
|
|
4
|
+
* This is `generate_library_json.py`'s `parse_args()` plus the part of `main()`
|
|
5
|
+
* that {@link buildLibrary} deliberately leaves out — the two banner lines, the
|
|
6
|
+
* cache lifecycle, and the exit code. The flag surface is the Python's one for
|
|
7
|
+
* one, because the pipeline that calls it is a YAML file nobody wants to edit
|
|
8
|
+
* twice; a flag argparse would have rejected is rejected here with exit 2.
|
|
9
|
+
*
|
|
10
|
+
* Exposed as `run(argv)` so the umbrella CLI can mount it the way it mounts
|
|
11
|
+
* every other registry verb. The optional `deps` argument exists for tests: a
|
|
12
|
+
* replay client and a recording reporter make the whole verb run without a
|
|
13
|
+
* tenant, which is the only way its exit codes can be pinned.
|
|
14
|
+
*/
|
|
15
|
+
import { rmSync } from "node:fs";
|
|
16
|
+
import { UsageError, exitCodeOf, messageOf } from "../errors.js";
|
|
17
|
+
import { consoleReporter } from "../reporter.js";
|
|
18
|
+
import { OfflineUipClient, defaultUipClient } from "../uip/client.js";
|
|
19
|
+
import { FsResponseCache } from "../uip/response-cache.js";
|
|
20
|
+
import { buildLibrary, parseConnectorsFlag } from "./build.js";
|
|
21
|
+
/** argparse's defaults, verbatim. */
|
|
22
|
+
export const DEFAULTS = {
|
|
23
|
+
outputDir: "./library",
|
|
24
|
+
cacheDir: "./.registry-cache",
|
|
25
|
+
isCacheDir: "./.is-cache",
|
|
26
|
+
connectorsCacheDir: "./.is-connectors-cache",
|
|
27
|
+
catalogScope: "all",
|
|
28
|
+
concurrency: 10,
|
|
29
|
+
};
|
|
30
|
+
const CATALOG_SCOPES = ["all", "tier1", "tier2"];
|
|
31
|
+
const USAGE = [
|
|
32
|
+
"Usage: flow-sdk registry build-library [--output-dir <dir>] [--cache-dir <dir>] [--is-cache-dir <dir>]",
|
|
33
|
+
" [--connectors-cache-dir <dir>] [--triggers-output <path>]",
|
|
34
|
+
" [--connectors a,b] [--catalog-scope all|tier1|tier2] [--concurrency <n>]",
|
|
35
|
+
" [--skip-enrichment] [--skip-connector-enrichment]",
|
|
36
|
+
" [--skip-generic-expansion] [--keep-temp] [--offline]",
|
|
37
|
+
].join("\n");
|
|
38
|
+
const VALUED = new Set([
|
|
39
|
+
"--output-dir",
|
|
40
|
+
"--cache-dir",
|
|
41
|
+
"--is-cache-dir",
|
|
42
|
+
"--connectors-cache-dir",
|
|
43
|
+
"--triggers-output",
|
|
44
|
+
"--connectors",
|
|
45
|
+
"--catalog-scope",
|
|
46
|
+
"--concurrency",
|
|
47
|
+
]);
|
|
48
|
+
const SWITCHES = new Set(["--skip-enrichment", "--skip-connector-enrichment", "--skip-generic-expansion", "--keep-temp", "--offline"]);
|
|
49
|
+
/**
|
|
50
|
+
* `int(text)`, narrowed on purpose: an optionally signed run of ASCII digits,
|
|
51
|
+
* ASCII whitespace allowed around it. Python's `int()` also takes `_`
|
|
52
|
+
* separators (`1_0`) and non-ASCII decimal digits (`١٠`); a pipeline YAML
|
|
53
|
+
* never spells a worker count that way, and accepting it would only make a
|
|
54
|
+
* typo parse. What IS mirrored is the refusal of zero and negatives, below.
|
|
55
|
+
*
|
|
56
|
+
* The sign is only reachable as `--concurrency=-3`: the loop below reads any
|
|
57
|
+
* `-…` as the next flag, so `--concurrency -3` is "expected one argument"
|
|
58
|
+
* where argparse's negative-number special case gave `int("-3")`. Both are a
|
|
59
|
+
* usage error and exit 2 before the build starts, and the alternative is to
|
|
60
|
+
* change how every valued flag reads its value for a number that is then
|
|
61
|
+
* refused anyway.
|
|
62
|
+
*/
|
|
63
|
+
const PY_INT = /^\s*[+-]?\d+\s*$/;
|
|
64
|
+
/**
|
|
65
|
+
* The options for this argv, or a {@link UsageError} carrying argparse's
|
|
66
|
+
* wording. Both `--flag value` and `--flag=value` are accepted, as argparse
|
|
67
|
+
* accepts them; anything that is neither a known flag nor a flag's value is an
|
|
68
|
+
* unrecognized argument, because the generator takes no positionals.
|
|
69
|
+
*/
|
|
70
|
+
export function parseArgs(argv) {
|
|
71
|
+
const values = new Map();
|
|
72
|
+
const switches = new Set();
|
|
73
|
+
const unrecognized = [];
|
|
74
|
+
for (let i = 0; i < argv.length; i++) {
|
|
75
|
+
const arg = argv[i];
|
|
76
|
+
const eq = arg.startsWith("--") ? arg.indexOf("=") : -1;
|
|
77
|
+
const name = eq >= 0 ? arg.slice(0, eq) : arg;
|
|
78
|
+
if (VALUED.has(name)) {
|
|
79
|
+
if (eq >= 0) {
|
|
80
|
+
values.set(name, arg.slice(eq + 1));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const next = argv[i + 1];
|
|
84
|
+
// argparse refuses to read another flag as a value.
|
|
85
|
+
if (next === undefined || (next.startsWith("-") && next !== "-")) {
|
|
86
|
+
throw new UsageError(`argument ${name}: expected one argument`);
|
|
87
|
+
}
|
|
88
|
+
values.set(name, next);
|
|
89
|
+
i += 1;
|
|
90
|
+
}
|
|
91
|
+
else if (SWITCHES.has(name) && eq < 0) {
|
|
92
|
+
switches.add(name);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
unrecognized.push(arg);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (unrecognized.length > 0)
|
|
99
|
+
throw new UsageError(`unrecognized arguments: ${unrecognized.join(" ")}`);
|
|
100
|
+
const catalogScope = values.get("--catalog-scope") ?? DEFAULTS.catalogScope;
|
|
101
|
+
if (!CATALOG_SCOPES.includes(catalogScope)) {
|
|
102
|
+
throw new UsageError(`argument --catalog-scope: invalid choice: '${catalogScope}' (choose from ${CATALOG_SCOPES.map((s) => `'${s}'`).join(", ")})`);
|
|
103
|
+
}
|
|
104
|
+
const concurrencyText = values.get("--concurrency");
|
|
105
|
+
let concurrency = DEFAULTS.concurrency;
|
|
106
|
+
if (concurrencyText !== undefined) {
|
|
107
|
+
if (!PY_INT.test(concurrencyText))
|
|
108
|
+
throw new UsageError(`argument --concurrency: invalid int value: '${concurrencyText}'`);
|
|
109
|
+
concurrency = parseInt(concurrencyText, 10);
|
|
110
|
+
// argparse accepted `0` and `-3`; the first `ThreadPoolExecutor(max_workers=…)`
|
|
111
|
+
// then raised `ValueError: max_workers must be greater than 0` — a traceback
|
|
112
|
+
// and exit 1, minutes into the build. The refusal is kept, moved to where
|
|
113
|
+
// the flag is read: a usage error (exit 2) before anything runs.
|
|
114
|
+
if (concurrency < 1)
|
|
115
|
+
throw new UsageError(`argument --concurrency: must be greater than 0, got ${concurrency}`);
|
|
116
|
+
}
|
|
117
|
+
// `if args.connectors:` tested the RAW string, so `--connectors ""` is a
|
|
118
|
+
// full build while `--connectors ,` is a curated subset of nothing. The
|
|
119
|
+
// split-and-strip happens only once the string has passed that gate.
|
|
120
|
+
const connectorsText = values.get("--connectors");
|
|
121
|
+
const connectors = connectorsText ? parseConnectorsFlag(connectorsText) : undefined;
|
|
122
|
+
return {
|
|
123
|
+
outputDir: values.get("--output-dir") ?? DEFAULTS.outputDir,
|
|
124
|
+
cacheDir: values.get("--cache-dir") ?? DEFAULTS.cacheDir,
|
|
125
|
+
isCacheDir: values.get("--is-cache-dir") ?? DEFAULTS.isCacheDir,
|
|
126
|
+
connectorsCacheDir: values.get("--connectors-cache-dir") ?? DEFAULTS.connectorsCacheDir,
|
|
127
|
+
...(values.has("--triggers-output") ? { triggersOutput: values.get("--triggers-output") } : {}),
|
|
128
|
+
...(connectors !== undefined ? { connectors } : {}),
|
|
129
|
+
catalogScope: catalogScope,
|
|
130
|
+
concurrency,
|
|
131
|
+
skipEnrichment: switches.has("--skip-enrichment"),
|
|
132
|
+
skipConnectorEnrichment: switches.has("--skip-connector-enrichment"),
|
|
133
|
+
skipGenericExpansion: switches.has("--skip-generic-expansion"),
|
|
134
|
+
keepTemp: switches.has("--keep-temp"),
|
|
135
|
+
offline: switches.has("--offline"),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export async function run(argv, deps = {}) {
|
|
139
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
140
|
+
console.log(USAGE);
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
let options;
|
|
144
|
+
try {
|
|
145
|
+
options = parseArgs(argv);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error(messageOf(error));
|
|
149
|
+
console.error(USAGE);
|
|
150
|
+
return 2;
|
|
151
|
+
}
|
|
152
|
+
const reporter = deps.reporter ?? consoleReporter;
|
|
153
|
+
reporter.info(`Cache directory: ${options.cacheDir}`);
|
|
154
|
+
reporter.info(`Output directory: ${options.outputDir}`);
|
|
155
|
+
try {
|
|
156
|
+
await buildLibrary(options, {
|
|
157
|
+
client: deps.client ?? (options.offline ? new OfflineUipClient() : defaultUipClient()),
|
|
158
|
+
caches: {
|
|
159
|
+
registry: new FsResponseCache(options.cacheDir),
|
|
160
|
+
is: new FsResponseCache(options.isCacheDir),
|
|
161
|
+
connectors: new FsResponseCache(options.connectorsCacheDir),
|
|
162
|
+
},
|
|
163
|
+
reporter,
|
|
164
|
+
concurrency: options.concurrency,
|
|
165
|
+
});
|
|
166
|
+
// The caches are a re-run aid, not a product: a build that got this far
|
|
167
|
+
// has no use for them unless asked to keep them. A build that failed above
|
|
168
|
+
// keeps them regardless, as the Python did, so the retry is cheap.
|
|
169
|
+
if (!options.keepTemp) {
|
|
170
|
+
reporter.info("Cleaning up caches...");
|
|
171
|
+
for (const dir of [options.cacheDir, options.isCacheDir, options.connectorsCacheDir]) {
|
|
172
|
+
rmSync(dir, { recursive: true, force: true });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
reporter.info("Done!");
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
console.error(messageOf(error));
|
|
180
|
+
return exitCodeOf(error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Reporter } from "../reporter.js";
|
|
2
|
+
import type { UipClient } from "../uip/client.js";
|
|
3
|
+
import { type ResponseCache } from "../uip/response-cache.js";
|
|
4
|
+
export interface BuildCaches {
|
|
5
|
+
/** `--cache-dir`: raw `flow registry get` stdout plus `_search_results.json`. */
|
|
6
|
+
registry: ResponseCache;
|
|
7
|
+
/** `--is-cache-dir`: `is resources describe/list` and `is triggers` payloads. */
|
|
8
|
+
is: ResponseCache;
|
|
9
|
+
/** `--connectors-cache-dir`: `is connectors metadata` payloads. */
|
|
10
|
+
connectors: ResponseCache;
|
|
11
|
+
}
|
|
12
|
+
export interface BuildPorts {
|
|
13
|
+
client: UipClient;
|
|
14
|
+
caches: BuildCaches;
|
|
15
|
+
reporter: Reporter;
|
|
16
|
+
/** Parallel remote calls, as `--concurrency`. */
|
|
17
|
+
concurrency: number;
|
|
18
|
+
/** Kill a `uip` call after this long. Unset means no limit, as the Python had none. */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
}
|
|
21
|
+
/** One describe that failed while parent fields were set: `(connector, object, operation, message)`. */
|
|
22
|
+
export type FailedFieldDescribe = readonly [
|
|
23
|
+
connectorKey: string,
|
|
24
|
+
objectName: string,
|
|
25
|
+
operation: string,
|
|
26
|
+
message: string
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* What the Python kept in module globals, plus the ports.
|
|
30
|
+
*
|
|
31
|
+
* `connectionId` routes every registry get / describe / list through
|
|
32
|
+
* `--connection-id`; `parentFields` are forwarded as `-f name=value` on
|
|
33
|
+
* describes and discriminate their cache key; `failedFieldDescribes` collects
|
|
34
|
+
* the CLI's own rejection message for each describe that failed under `-f`,
|
|
35
|
+
* because the pipeline otherwise swallows it (see `isDescribeOperation`).
|
|
36
|
+
*/
|
|
37
|
+
export interface BuildContext extends BuildPorts {
|
|
38
|
+
connectionId?: string;
|
|
39
|
+
/** Insertion order is the `-f` order on the command line. */
|
|
40
|
+
parentFields: Map<string, string>;
|
|
41
|
+
failedFieldDescribes: FailedFieldDescribe[];
|
|
42
|
+
}
|
|
43
|
+
export interface BuildScope {
|
|
44
|
+
connectionId?: string;
|
|
45
|
+
parentFields?: ReadonlyMap<string, string> | Readonly<Record<string, string>>;
|
|
46
|
+
}
|
|
47
|
+
export declare function createBuildContext(ports: BuildPorts, scope?: BuildScope): BuildContext;
|
|
48
|
+
/** `_schema_cache_scope()`: static and per-connection responses never share a cache. */
|
|
49
|
+
export declare function schemaCacheScope(ctx: BuildContext): string;
|
|
50
|
+
/**
|
|
51
|
+
* `_field_scope()`: `f-` + the first 12 hex digits of the sha256 over
|
|
52
|
+
* `name=value` pairs sorted by name and joined with NUL; empty when no parent
|
|
53
|
+
* field is set. The describe answer is a function of these values, so a cache
|
|
54
|
+
* keyed only on (connection, object, operation) would serve the first variant
|
|
55
|
+
* for every later one.
|
|
56
|
+
*/
|
|
57
|
+
export declare function fieldScope(parentFields: ReadonlyMap<string, string>): string;
|
|
58
|
+
/** Cache file for one `flow registry get`: the node type with `.` → `_`. */
|
|
59
|
+
export declare function registryCacheName(nodeType: string): string;
|
|
60
|
+
export declare const SEARCH_RESULTS_NAME = "_search_results.json";
|
|
61
|
+
/** `json.dump(payload, f)`: cache bytes shaped as Python wrote them. */
|
|
62
|
+
export declare function writeCache(cache: ResponseCache, name: string, payload: unknown): void;
|
|
63
|
+
/**
|
|
64
|
+
* `registry_get`: cached `uip maestro flow registry get <nodeType>`.
|
|
65
|
+
*
|
|
66
|
+
* Returns the cache name the raw stdout lives under, or `undefined` when the
|
|
67
|
+
* call failed. `quiet` suppresses the failure WARN — for a caller probing which
|
|
68
|
+
* of several node-type namespaces an action lives in, where a miss is an
|
|
69
|
+
* expected answer rather than a problem to report.
|
|
70
|
+
*/
|
|
71
|
+
export declare function registryGet(ctx: BuildContext, nodeType: string, quiet?: boolean): Promise<string | undefined>;
|
|
72
|
+
/**
|
|
73
|
+
* `is_describe_operation`: cached `uip is resources describe <connector>
|
|
74
|
+
* <object> --operation <op>` (plus `--connection-id` and `-f` when set).
|
|
75
|
+
*
|
|
76
|
+
* Returns the payload's `Data` on success, or `undefined` on any failure. A
|
|
77
|
+
* failure is cached too, with a sentinel that keeps the CLI's `Message`: an
|
|
78
|
+
* incomplete parent set is rejected with a helpful message the pipeline would
|
|
79
|
+
* otherwise swallow, so it is recorded on the context while parent fields are
|
|
80
|
+
* set — from a fresh call and from a cached failure alike.
|
|
81
|
+
*/
|
|
82
|
+
export declare function isDescribeOperation(ctx: BuildContext, connectorKey: string, objectName: string, operation: string): Promise<unknown>;
|
|
83
|
+
/**
|
|
84
|
+
* `is_describe_object`: cached `uip is resources describe <connector> <object>`
|
|
85
|
+
* with no `--operation`. Its `Data` carries `AvailableOperations`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function isDescribeObject(ctx: BuildContext, connectorKey: string, objectName: string): Promise<unknown>;
|
|
88
|
+
/**
|
|
89
|
+
* `is_resources_list`: cached `uip is resources list <connector>` — the object
|
|
90
|
+
* catalog, each row `Name`/`DisplayName`/`Path`/`Type`/`SubType`. The list on
|
|
91
|
+
* success (possibly empty), `undefined` on failure.
|
|
92
|
+
*
|
|
93
|
+
* `refresh` bypasses BOTH caches — this one and the CLI's own, which never
|
|
94
|
+
* invalidates itself: measured on uipath-salesforce-sfdc, 18 objects stale and
|
|
95
|
+
* 864 with `--refresh`.
|
|
96
|
+
*/
|
|
97
|
+
export declare function isResourcesList(ctx: BuildContext, connectorKey: string, options?: {
|
|
98
|
+
operation?: string | null;
|
|
99
|
+
refresh?: boolean;
|
|
100
|
+
}): Promise<unknown[] | undefined>;
|
|
101
|
+
/**
|
|
102
|
+
* `is_connector_get`: cached `uip is connectors metadata <key>`, answering the
|
|
103
|
+
* first element of `Data` or `undefined`. The legacy `connectors get` cache
|
|
104
|
+
* files are deliberately not reused: that output omitted the discovery
|
|
105
|
+
* capabilities and would silently mark every connector static.
|
|
106
|
+
*/
|
|
107
|
+
export declare function isConnectorGet(ctx: BuildContext, connectorKey: string): Promise<unknown>;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The build's connection to the tenant: one `uip` client, three response caches,
|
|
3
|
+
* and the scope every call is made under.
|
|
4
|
+
*
|
|
5
|
+
* The Python generator kept `_CONNECTION_ID`, `_PARENT_FIELDS` and
|
|
6
|
+
* `_FAILED_FIELD_DESCRIBES` as module globals that `prepare_connector` set before
|
|
7
|
+
* calling in. Here they ride on a {@link BuildContext} that every remote call
|
|
8
|
+
* takes as its first argument, so two builds in one process cannot see each
|
|
9
|
+
* other's connection, and a test can hand in a context that never reaches the
|
|
10
|
+
* network.
|
|
11
|
+
*
|
|
12
|
+
* Cache file names and the `Result: Failure` sentinels are the Python's exactly:
|
|
13
|
+
* a `--keep-temp` cache the Python wrote drives this code to the same bytes,
|
|
14
|
+
* which is how the port is proven.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
17
|
+
import { pyJsonStringify } from "../codecs/pyjson.js";
|
|
18
|
+
import { sortedByKeys } from "../compat/compare.js";
|
|
19
|
+
import { isConnectorsMetadata, isResourcesDescribeObject, isResourcesDescribeOperation, isResourcesList as isResourcesListArgv, registryGet as registryGetArgv, } from "../uip/commands.js";
|
|
20
|
+
import { CACHED_FAILURE, isCachedFailure, safeCacheName } from "../uip/response-cache.js";
|
|
21
|
+
import { pyStrip } from "../compat/pystr.js";
|
|
22
|
+
import { get, isRecord, pyOr, truthy } from "./py.js";
|
|
23
|
+
export function createBuildContext(ports, scope = {}) {
|
|
24
|
+
const parentFields = scope.parentFields instanceof Map
|
|
25
|
+
? new Map(scope.parentFields)
|
|
26
|
+
: new Map(Object.entries(scope.parentFields ?? {}));
|
|
27
|
+
return {
|
|
28
|
+
...ports,
|
|
29
|
+
...(scope.connectionId ? { connectionId: scope.connectionId } : {}),
|
|
30
|
+
parentFields,
|
|
31
|
+
failedFieldDescribes: [],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** `_schema_cache_scope()`: static and per-connection responses never share a cache. */
|
|
35
|
+
export function schemaCacheScope(ctx) {
|
|
36
|
+
return ctx.connectionId || "_static";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* `_field_scope()`: `f-` + the first 12 hex digits of the sha256 over
|
|
40
|
+
* `name=value` pairs sorted by name and joined with NUL; empty when no parent
|
|
41
|
+
* field is set. The describe answer is a function of these values, so a cache
|
|
42
|
+
* keyed only on (connection, object, operation) would serve the first variant
|
|
43
|
+
* for every later one.
|
|
44
|
+
*/
|
|
45
|
+
export function fieldScope(parentFields) {
|
|
46
|
+
if (parentFields.size === 0)
|
|
47
|
+
return "";
|
|
48
|
+
const pairs = sortedByKeys([...parentFields.entries()], ([k]) => k, ([, v]) => v);
|
|
49
|
+
const flat = pairs.map(([k, v]) => `${k}=${v}`).join("\0");
|
|
50
|
+
return `f-${createHash("sha256").update(flat, "utf8").digest("hex").slice(0, 12)}`;
|
|
51
|
+
}
|
|
52
|
+
/** Cache file for one `flow registry get`: the node type with `.` → `_`. */
|
|
53
|
+
export function registryCacheName(nodeType) {
|
|
54
|
+
return `${nodeType.replaceAll(".", "_")}.json`;
|
|
55
|
+
}
|
|
56
|
+
export const SEARCH_RESULTS_NAME = "_search_results.json";
|
|
57
|
+
function runUip(ctx, argv) {
|
|
58
|
+
return ctx.client.run(argv, ctx.timeoutMs === undefined ? undefined : { timeoutMs: ctx.timeoutMs });
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `json.loads(result.stdout)`: the whole of stdout as one document, or
|
|
62
|
+
* `undefined` when it is not one. Deliberately not the lenient banner-skipping
|
|
63
|
+
* parser — the Python parsed the full stream and treated anything else as a
|
|
64
|
+
* failed call, and a call that fails there must fail here.
|
|
65
|
+
*/
|
|
66
|
+
function parseStdout(stdout) {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(stdout);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** `json.dump(payload, f)`: cache bytes shaped as Python wrote them. */
|
|
75
|
+
export function writeCache(cache, name, payload) {
|
|
76
|
+
cache.write(name, payload, pyJsonStringify(payload));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* True when the call never ran, so nothing about it may be written down.
|
|
80
|
+
*
|
|
81
|
+
* Each fetcher below remembers a FAILURE as a `Result: Failure` sentinel, and
|
|
82
|
+
* a failure is only ever the tenant's answer — the Python had no offline mode,
|
|
83
|
+
* so every failure it cached was one. Under `--offline` the client refuses
|
|
84
|
+
* instead, and caching that as a failure would make the next ONLINE build over
|
|
85
|
+
* the same `--keep-temp` caches read the refusal as "this object has no
|
|
86
|
+
* schema" and carry on, silently.
|
|
87
|
+
*
|
|
88
|
+
* This is checked EXPLICITLY, before the parse, rather than resting on the
|
|
89
|
+
* parse failing: the four writes below are gated on `parseStdout` succeeding,
|
|
90
|
+
* and they stay safe only because `OfflineUipClient` happens to emit empty
|
|
91
|
+
* output. That accident is exactly what the offline work set out to remove, and
|
|
92
|
+
* `events.ts` already refuses to rest on it for the two trigger caches.
|
|
93
|
+
*/
|
|
94
|
+
function refused(result) {
|
|
95
|
+
return result.refused === true;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* `"__".join(parts)` raises `TypeError` on a non-str part, and the Python
|
|
99
|
+
* generator relied on that: an entry whose `objectName` is `null` never
|
|
100
|
+
* reached the CLI (its enrichment failed and was reported). `Array.join`
|
|
101
|
+
* would coerce `null` to `""` and issue a describe the Python never made.
|
|
102
|
+
*/
|
|
103
|
+
function cacheNameOf(...parts) {
|
|
104
|
+
parts.forEach((part, i) => {
|
|
105
|
+
if (typeof part !== "string") {
|
|
106
|
+
const kind = part === null || part === undefined ? "NoneType" : typeof part === "number" ? "int" : typeof part;
|
|
107
|
+
throw new TypeError(`sequence item ${i}: expected str instance, ${kind} found`);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return `${safeCacheName(...parts)}.json`;
|
|
111
|
+
}
|
|
112
|
+
/** `payload.get("Result")` on something that is not a dict raises in Python. */
|
|
113
|
+
function envelope(payload) {
|
|
114
|
+
if (!isRecord(payload))
|
|
115
|
+
throw new TypeError(`'${Array.isArray(payload) ? "list" : typeof payload}' object has no attribute 'get'`);
|
|
116
|
+
return payload;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* `registry_get`: cached `uip maestro flow registry get <nodeType>`.
|
|
120
|
+
*
|
|
121
|
+
* Returns the cache name the raw stdout lives under, or `undefined` when the
|
|
122
|
+
* call failed. `quiet` suppresses the failure WARN — for a caller probing which
|
|
123
|
+
* of several node-type namespaces an action lives in, where a miss is an
|
|
124
|
+
* expected answer rather than a problem to report.
|
|
125
|
+
*/
|
|
126
|
+
export async function registryGet(ctx, nodeType, quiet = false) {
|
|
127
|
+
const name = registryCacheName(nodeType);
|
|
128
|
+
if (ctx.caches.registry.has(name))
|
|
129
|
+
return name;
|
|
130
|
+
const result = await runUip(ctx, registryGetArgv(nodeType, ctx.connectionId));
|
|
131
|
+
if (result.code !== 0) {
|
|
132
|
+
if (!quiet)
|
|
133
|
+
ctx.reporter.warn(` WARN: registry get failed for ${nodeType}: ${pyStrip(result.stderr)}`);
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
ctx.caches.registry.write(name, undefined, result.stdout);
|
|
137
|
+
return name;
|
|
138
|
+
}
|
|
139
|
+
function noteFailedFieldDescribe(ctx, connectorKey, objectName, operation, message) {
|
|
140
|
+
if (ctx.parentFields.size > 0) {
|
|
141
|
+
ctx.failedFieldDescribes.push([connectorKey, objectName, operation, typeof message === "string" && message ? message : ""]);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* `is_describe_operation`: cached `uip is resources describe <connector>
|
|
146
|
+
* <object> --operation <op>` (plus `--connection-id` and `-f` when set).
|
|
147
|
+
*
|
|
148
|
+
* Returns the payload's `Data` on success, or `undefined` on any failure. A
|
|
149
|
+
* failure is cached too, with a sentinel that keeps the CLI's `Message`: an
|
|
150
|
+
* incomplete parent set is rejected with a helpful message the pipeline would
|
|
151
|
+
* otherwise swallow, so it is recorded on the context while parent fields are
|
|
152
|
+
* set — from a fresh call and from a cached failure alike.
|
|
153
|
+
*/
|
|
154
|
+
export async function isDescribeOperation(ctx, connectorKey, objectName, operation) {
|
|
155
|
+
const parts = [schemaCacheScope(ctx), connectorKey, objectName, operation];
|
|
156
|
+
const scope = fieldScope(ctx.parentFields);
|
|
157
|
+
if (scope)
|
|
158
|
+
parts.push(scope);
|
|
159
|
+
const name = cacheNameOf(...parts);
|
|
160
|
+
if (ctx.caches.is.has(name)) {
|
|
161
|
+
const cached = ctx.caches.is.read(name);
|
|
162
|
+
if (isCachedFailure(cached))
|
|
163
|
+
noteFailedFieldDescribe(ctx, connectorKey, objectName, operation, get(cached, "Message"));
|
|
164
|
+
return isRecord(cached) && cached.Data !== undefined ? cached.Data : undefined;
|
|
165
|
+
}
|
|
166
|
+
const result = await runUip(ctx, isResourcesDescribeOperation(connectorKey, objectName, operation, ctx.connectionId, ctx.parentFields));
|
|
167
|
+
if (refused(result))
|
|
168
|
+
return undefined;
|
|
169
|
+
const parsed = parseStdout(result.stdout);
|
|
170
|
+
if (parsed === undefined)
|
|
171
|
+
return undefined;
|
|
172
|
+
const payload = envelope(parsed);
|
|
173
|
+
if (get(payload, "Result") !== "Success") {
|
|
174
|
+
noteFailedFieldDescribe(ctx, connectorKey, objectName, operation, get(payload, "Message"));
|
|
175
|
+
writeCache(ctx.caches.is, name, { Result: "Failure", [CACHED_FAILURE]: true, Message: get(payload, "Message") });
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
writeCache(ctx.caches.is, name, payload);
|
|
179
|
+
return payload.Data;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* `is_describe_object`: cached `uip is resources describe <connector> <object>`
|
|
183
|
+
* with no `--operation`. Its `Data` carries `AvailableOperations`.
|
|
184
|
+
*/
|
|
185
|
+
export async function isDescribeObject(ctx, connectorKey, objectName) {
|
|
186
|
+
const name = cacheNameOf(schemaCacheScope(ctx), connectorKey, objectName, "_operations");
|
|
187
|
+
if (ctx.caches.is.has(name)) {
|
|
188
|
+
const cached = ctx.caches.is.read(name);
|
|
189
|
+
return isRecord(cached) && cached.Data !== undefined ? cached.Data : undefined;
|
|
190
|
+
}
|
|
191
|
+
const result = await runUip(ctx, isResourcesDescribeObject(connectorKey, objectName, ctx.connectionId));
|
|
192
|
+
if (refused(result))
|
|
193
|
+
return undefined;
|
|
194
|
+
const parsed = parseStdout(result.stdout);
|
|
195
|
+
if (parsed === undefined)
|
|
196
|
+
return undefined;
|
|
197
|
+
const payload = envelope(parsed);
|
|
198
|
+
if (get(payload, "Result") !== "Success") {
|
|
199
|
+
writeCache(ctx.caches.is, name, { Result: "Failure", [CACHED_FAILURE]: true });
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
writeCache(ctx.caches.is, name, payload);
|
|
203
|
+
return payload.Data;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* `is_resources_list`: cached `uip is resources list <connector>` — the object
|
|
207
|
+
* catalog, each row `Name`/`DisplayName`/`Path`/`Type`/`SubType`. The list on
|
|
208
|
+
* success (possibly empty), `undefined` on failure.
|
|
209
|
+
*
|
|
210
|
+
* `refresh` bypasses BOTH caches — this one and the CLI's own, which never
|
|
211
|
+
* invalidates itself: measured on uipath-salesforce-sfdc, 18 objects stale and
|
|
212
|
+
* 864 with `--refresh`.
|
|
213
|
+
*/
|
|
214
|
+
export async function isResourcesList(ctx, connectorKey, options = {}) {
|
|
215
|
+
const operation = options.operation ?? undefined;
|
|
216
|
+
const name = `${safeCacheName(schemaCacheScope(ctx), connectorKey, pyOr(operation, "_all_operations"), "_resources_list")}.json`;
|
|
217
|
+
if (!options.refresh && ctx.caches.is.has(name)) {
|
|
218
|
+
const cached = ctx.caches.is.read(name);
|
|
219
|
+
const data = get(cached, "Data");
|
|
220
|
+
return Array.isArray(data) ? data : undefined;
|
|
221
|
+
}
|
|
222
|
+
const result = await runUip(ctx, isResourcesListArgv(connectorKey, {
|
|
223
|
+
...(truthy(operation) ? { operation } : {}),
|
|
224
|
+
...(options.refresh ? { refresh: true } : {}),
|
|
225
|
+
connectionId: ctx.connectionId,
|
|
226
|
+
}));
|
|
227
|
+
if (refused(result))
|
|
228
|
+
return undefined;
|
|
229
|
+
const parsed = parseStdout(result.stdout);
|
|
230
|
+
if (parsed === undefined)
|
|
231
|
+
return undefined;
|
|
232
|
+
const payload = envelope(parsed);
|
|
233
|
+
if (get(payload, "Result") !== "Success") {
|
|
234
|
+
writeCache(ctx.caches.is, name, { Result: "Failure", [CACHED_FAILURE]: true });
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
writeCache(ctx.caches.is, name, payload);
|
|
238
|
+
return Array.isArray(payload.Data) ? payload.Data : undefined;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* `is_connector_get`: cached `uip is connectors metadata <key>`, answering the
|
|
242
|
+
* first element of `Data` or `undefined`. The legacy `connectors get` cache
|
|
243
|
+
* files are deliberately not reused: that output omitted the discovery
|
|
244
|
+
* capabilities and would silently mark every connector static.
|
|
245
|
+
*/
|
|
246
|
+
export async function isConnectorGet(ctx, connectorKey) {
|
|
247
|
+
const name = `${safeCacheName(connectorKey, "_connector_metadata")}.json`;
|
|
248
|
+
const firstRow = (payload) => {
|
|
249
|
+
const data = pyOr(get(payload, "Data"), []);
|
|
250
|
+
return Array.isArray(data) && data.length > 0 ? data[0] : undefined;
|
|
251
|
+
};
|
|
252
|
+
if (ctx.caches.connectors.has(name))
|
|
253
|
+
return firstRow(ctx.caches.connectors.read(name));
|
|
254
|
+
const result = await runUip(ctx, isConnectorsMetadata(connectorKey));
|
|
255
|
+
if (refused(result))
|
|
256
|
+
return undefined;
|
|
257
|
+
const parsed = parseStdout(result.stdout);
|
|
258
|
+
if (parsed === undefined)
|
|
259
|
+
return undefined;
|
|
260
|
+
const payload = envelope(parsed);
|
|
261
|
+
if (get(payload, "Result") !== "Success") {
|
|
262
|
+
writeCache(ctx.caches.connectors, name, { Result: "Failure", [CACHED_FAILURE]: true });
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
writeCache(ctx.caches.connectors, name, payload);
|
|
266
|
+
return firstRow(payload);
|
|
267
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { LibraryEntry } from "../model/library.js";
|
|
2
|
+
import { type BuildContext } from "./context.js";
|
|
3
|
+
/**
|
|
4
|
+
* Registry `httpMethod` (e.g. `GETBYID`) → a guess at the `is resources`
|
|
5
|
+
* operation name, for an entry whose canonical `operation.name` is empty.
|
|
6
|
+
*/
|
|
7
|
+
export declare const HTTP_METHOD_TO_OPERATION: ReadonlyMap<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* `discover_operation_name`: the `is resources` operation whose HTTP method
|
|
10
|
+
* matches the entry's, from the object's `AvailableOperations`; `null` when
|
|
11
|
+
* the object cannot be described or nothing matches.
|
|
12
|
+
*/
|
|
13
|
+
export declare function discoverOperationName(ctx: BuildContext, entry: LibraryEntry): Promise<unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* The pure half of `enrich_entry`: merge one describe `Data` payload into the
|
|
16
|
+
* entry, in place. `operation.name` is filled only when the registry left it
|
|
17
|
+
* empty; `pathTemplate`, `parameters` and the two schemas come from the
|
|
18
|
+
* payload; `objectDisplayName` and `display.operationLabel` fill gaps only.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyDescribe(entry: LibraryEntry, data: unknown): LibraryEntry;
|
|
21
|
+
/**
|
|
22
|
+
* `enrich_entry`: augment a canonical entry with `is resources describe` data.
|
|
23
|
+
* On any failure the entry is returned as it was, so the pipeline degrades
|
|
24
|
+
* gracefully.
|
|
25
|
+
*
|
|
26
|
+
* The registry's verb and the IS CLI's can DISAGREE for the same operation
|
|
27
|
+
* (Data Service `QueryEntityRecordsCurated`: registry `List`, CLI `Create`).
|
|
28
|
+
* When the registry's name does not resolve, the OBJECT is asked which
|
|
29
|
+
* operations it has and the one whose HTTP method matches is retried.
|
|
30
|
+
* `operation.name` deliberately keeps the REGISTRY's verb even then — it maps
|
|
31
|
+
* to a CRUD verb the offline fixtures are synthesised from; the discovered
|
|
32
|
+
* name is only for reaching the schema.
|
|
33
|
+
*/
|
|
34
|
+
export declare function enrichEntry(ctx: BuildContext, entry: LibraryEntry): Promise<LibraryEntry>;
|
|
35
|
+
/** `enrich_all`: `enrichEntry` over every entry, results in input order. */
|
|
36
|
+
export declare function enrichAll(ctx: BuildContext, entries: readonly LibraryEntry[]): Promise<LibraryEntry[]>;
|