@uipath/maestro-builder-sdk 6.4.0 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/cli/commands/registry.js +68 -12
  2. package/dist/registry/archive/entry-policy.d.ts +36 -0
  3. package/dist/registry/archive/entry-policy.js +60 -0
  4. package/dist/registry/archive/extract.d.ts +31 -0
  5. package/dist/registry/archive/extract.js +92 -0
  6. package/dist/registry/archive/zip-reader.d.ts +38 -0
  7. package/dist/registry/archive/zip-reader.js +256 -0
  8. package/dist/registry/codecs/pyjson.d.ts +62 -0
  9. package/dist/registry/codecs/pyjson.js +208 -0
  10. package/dist/registry/compat/compare.d.ts +18 -0
  11. package/dist/registry/compat/compare.js +32 -0
  12. package/dist/registry/compat/paths.d.ts +4 -0
  13. package/dist/registry/compat/paths.js +17 -0
  14. package/dist/registry/compat/pystr.d.ts +50 -0
  15. package/dist/registry/compat/pystr.js +221 -0
  16. package/dist/registry/concurrency.d.ts +10 -0
  17. package/dist/registry/concurrency.js +34 -0
  18. package/dist/registry/curated-overlay.d.ts +36 -4
  19. package/dist/registry/curated-overlay.js +87 -14
  20. package/dist/registry/errors.d.ts +26 -0
  21. package/dist/registry/errors.js +38 -0
  22. package/dist/registry/extractor.d.ts +9 -10
  23. package/dist/registry/extractor.js +5 -15
  24. package/dist/registry/files.d.ts +26 -0
  25. package/dist/registry/files.js +160 -0
  26. package/dist/registry/generators/descriptors.d.ts +81 -0
  27. package/dist/registry/generators/descriptors.js +405 -0
  28. package/dist/registry/generators/fields.d.ts +46 -0
  29. package/dist/registry/generators/fields.js +111 -0
  30. package/dist/registry/generators/markdown/common.d.ts +21 -0
  31. package/dist/registry/generators/markdown/common.js +55 -0
  32. package/dist/registry/generators/markdown/index.d.ts +33 -0
  33. package/dist/registry/generators/markdown/index.js +37 -0
  34. package/dist/registry/generators/markdown/page.d.ts +8 -0
  35. package/dist/registry/generators/markdown/page.js +52 -0
  36. package/dist/registry/generators/markdown/pyvalue.d.ts +34 -0
  37. package/dist/registry/generators/markdown/pyvalue.js +106 -0
  38. package/dist/registry/generators/markdown/sections/choosing-object.d.ts +2 -0
  39. package/dist/registry/generators/markdown/sections/choosing-object.js +52 -0
  40. package/dist/registry/generators/markdown/sections/example.d.ts +22 -0
  41. package/dist/registry/generators/markdown/sections/example.js +295 -0
  42. package/dist/registry/generators/markdown/sections/filtering.d.ts +2 -0
  43. package/dist/registry/generators/markdown/sections/filtering.js +76 -0
  44. package/dist/registry/generators/markdown/sections/header.d.ts +2 -0
  45. package/dist/registry/generators/markdown/sections/header.js +37 -0
  46. package/dist/registry/generators/markdown/sections/inputs.d.ts +30 -0
  47. package/dist/registry/generators/markdown/sections/inputs.js +151 -0
  48. package/dist/registry/generators/markdown/sections/lookups.d.ts +12 -0
  49. package/dist/registry/generators/markdown/sections/lookups.js +150 -0
  50. package/dist/registry/generators/markdown/sections/outputs.d.ts +3 -0
  51. package/dist/registry/generators/markdown/sections/outputs.js +9 -0
  52. package/dist/registry/generators/markdown/sections/resolving-fields.d.ts +2 -0
  53. package/dist/registry/generators/markdown/sections/resolving-fields.js +139 -0
  54. package/dist/registry/generators/markdown/sections/schema-dynamic.d.ts +2 -0
  55. package/dist/registry/generators/markdown/sections/schema-dynamic.js +86 -0
  56. package/dist/registry/generators/materialize.d.ts +30 -0
  57. package/dist/registry/generators/materialize.js +132 -0
  58. package/dist/registry/generators/md-symbols.d.ts +22 -0
  59. package/dist/registry/generators/md-symbols.js +58 -0
  60. package/dist/registry/generators/triggers.d.ts +15 -0
  61. package/dist/registry/generators/triggers.js +85 -0
  62. package/dist/registry/generators/type-registry.d.ts +50 -0
  63. package/dist/registry/generators/type-registry.js +154 -0
  64. package/dist/registry/generators/type-tree.d.ts +65 -0
  65. package/dist/registry/generators/type-tree.js +179 -0
  66. package/dist/registry/library-build/build.d.ts +57 -0
  67. package/dist/registry/library-build/build.js +286 -0
  68. package/dist/registry/library-build/canonical.d.ts +119 -0
  69. package/dist/registry/library-build/canonical.js +512 -0
  70. package/dist/registry/library-build/cli.d.ts +45 -0
  71. package/dist/registry/library-build/cli.js +182 -0
  72. package/dist/registry/library-build/context.d.ts +107 -0
  73. package/dist/registry/library-build/context.js +267 -0
  74. package/dist/registry/library-build/enrich.d.ts +36 -0
  75. package/dist/registry/library-build/enrich.js +158 -0
  76. package/dist/registry/library-build/events.d.ts +108 -0
  77. package/dist/registry/library-build/events.js +476 -0
  78. package/dist/registry/library-build/generic-expand.d.ts +77 -0
  79. package/dist/registry/library-build/generic-expand.js +363 -0
  80. package/dist/registry/library-build/plan.d.ts +71 -0
  81. package/dist/registry/library-build/plan.js +270 -0
  82. package/dist/registry/library-build/py.d.ts +45 -0
  83. package/dist/registry/library-build/py.js +167 -0
  84. package/dist/registry/library-build/schema-action.d.ts +38 -0
  85. package/dist/registry/library-build/schema-action.js +107 -0
  86. package/dist/registry/library-build/write.d.ts +6 -0
  87. package/dist/registry/library-build/write.js +26 -0
  88. package/dist/registry/library-reader.d.ts +20 -0
  89. package/dist/registry/library-reader.js +50 -0
  90. package/dist/registry/lookup-specs.d.ts +55 -0
  91. package/dist/registry/lookup-specs.js +140 -0
  92. package/dist/registry/materialize-cli.js +28 -14
  93. package/dist/registry/materializer.d.ts +25 -3
  94. package/dist/registry/materializer.js +45 -29
  95. package/dist/registry/model/library.d.ts +254 -0
  96. package/dist/registry/model/library.js +23 -0
  97. package/dist/registry/naming.d.ts +54 -0
  98. package/dist/registry/naming.js +142 -0
  99. package/dist/registry/orphans.d.ts +4 -0
  100. package/dist/registry/orphans.js +86 -0
  101. package/dist/registry/prepare/actions.d.ts +26 -0
  102. package/dist/registry/prepare/actions.js +94 -0
  103. package/dist/registry/prepare/connections.d.ts +181 -0
  104. package/dist/registry/prepare/connections.js +399 -0
  105. package/dist/registry/prepare/event.d.ts +96 -0
  106. package/dist/registry/prepare/event.js +268 -0
  107. package/dist/registry/prepare/handoff.d.ts +21 -0
  108. package/dist/registry/prepare/handoff.js +91 -0
  109. package/dist/registry/prepare/ledger.d.ts +104 -0
  110. package/dist/registry/prepare/ledger.js +216 -0
  111. package/dist/registry/prepare/messages.d.ts +190 -0
  112. package/dist/registry/prepare/messages.js +472 -0
  113. package/dist/registry/prepare/objects.d.ts +130 -0
  114. package/dist/registry/prepare/objects.js +318 -0
  115. package/dist/registry/prepare/overlay.d.ts +149 -0
  116. package/dist/registry/prepare/overlay.js +487 -0
  117. package/dist/registry/prepare/parents.d.ts +41 -0
  118. package/dist/registry/prepare/parents.js +122 -0
  119. package/dist/registry/prepare/pipeline.d.ts +91 -0
  120. package/dist/registry/prepare/pipeline.js +376 -0
  121. package/dist/registry/prepare/regenerate.d.ts +9 -0
  122. package/dist/registry/prepare/regenerate.js +50 -0
  123. package/dist/registry/prepare/resolve.d.ts +199 -0
  124. package/dist/registry/prepare/resolve.js +470 -0
  125. package/dist/registry/prepare/retry.d.ts +83 -0
  126. package/dist/registry/prepare/retry.js +109 -0
  127. package/dist/registry/prepare/source-import.d.ts +54 -0
  128. package/dist/registry/prepare/source-import.js +192 -0
  129. package/dist/registry/prepare/support.d.ts +41 -0
  130. package/dist/registry/prepare/support.js +178 -0
  131. package/dist/registry/prepare-cli.d.ts +16 -5
  132. package/dist/registry/prepare-cli.js +60 -53
  133. package/dist/registry/pull-cli.js +8 -7
  134. package/dist/registry/reporter.d.ts +26 -0
  135. package/dist/registry/reporter.js +41 -0
  136. package/dist/registry/uip/client.d.ts +99 -0
  137. package/dist/registry/uip/client.js +226 -0
  138. package/dist/registry/uip/commands.d.ts +40 -0
  139. package/dist/registry/uip/commands.js +80 -0
  140. package/dist/registry/uip/envelope.d.ts +37 -0
  141. package/dist/registry/uip/envelope.js +84 -0
  142. package/dist/registry/uip/response-cache.d.ts +28 -0
  143. package/dist/registry/uip/response-cache.js +57 -0
  144. package/lib/README.md +10 -8
  145. package/package.json +3 -3
  146. package/dist/generators/_connections.py +0 -331
  147. package/dist/generators/_events.py +0 -355
  148. package/dist/generators/_lookups.py +0 -114
  149. package/dist/generators/_naming.py +0 -185
  150. package/dist/generators/_objects.py +0 -299
  151. package/dist/generators/_resolve.py +0 -319
  152. package/dist/generators/convert_library_to_md.py +0 -1441
  153. package/dist/generators/extract_library.py +0 -125
  154. package/dist/generators/generate_connectors_ts.py +0 -936
  155. package/dist/generators/generate_library_json.py +0 -2527
  156. package/dist/generators/generate_triggers_ts.py +0 -110
  157. package/dist/generators/materialize_registry.py +0 -155
  158. package/dist/generators/prepare_connector.py +0 -1860
  159. package/dist/registry/python.d.ts +0 -26
  160. package/dist/registry/python.js +0 -46
@@ -0,0 +1,91 @@
1
+ import { type BuildCaches, type BuildContext } from "../library-build/context.js";
2
+ import type { Reporter } from "../reporter.js";
3
+ import type { UipClient } from "../uip/client.js";
4
+ import { type CatalogueRow } from "./objects.js";
5
+ /** The command line, as `argparse` parsed it. Defaults are the Python's. */
6
+ export interface PrepareOptions {
7
+ connectorKey: string;
8
+ action: string;
9
+ /** Omit to discover the connection from `uip is connections list`. */
10
+ connectionId?: string;
11
+ /** `--connection <name>`: pick the connection by name when several match. */
12
+ connection?: string;
13
+ /** `--bindings` (default `./bindings.json`). */
14
+ bindings?: string;
15
+ /** `--bind-connection` (default: the connector's last dash-segment). */
16
+ bindConnection?: string;
17
+ /** `--bind-folder` (default `shared`). */
18
+ bindFolder?: string;
19
+ noBindings?: boolean;
20
+ /** `--object`; mutually exclusive with `allObjects`. */
21
+ objectName?: string;
22
+ allObjects?: boolean;
23
+ /** `-f NAME=VALUE`, repeatable, in the order given. */
24
+ fields?: readonly string[];
25
+ /** `--out` (default `./connectors-local`). */
26
+ out?: string;
27
+ /** `--source`: the `.flow.ts` whose import is repointed. */
28
+ source?: string;
29
+ noSourceRewrite?: boolean;
30
+ /** `--version`: pin an op version. */
31
+ version?: string;
32
+ /** `--import`: the module specifier the emitted `.ts` imports from (default {@link PACKAGE_NAME}). */
33
+ importSpecifier?: string;
34
+ /** `--resolve FIELD:BY=VALUE`, repeatable. */
35
+ resolve?: readonly string[];
36
+ refreshLookups?: boolean;
37
+ jsonOnly?: boolean;
38
+ }
39
+ export interface PreparePorts {
40
+ client: UipClient;
41
+ reporter: Reporter;
42
+ /** Response caches for this run; in-memory ones by default (the Python used a temp dir). */
43
+ caches?: BuildCaches;
44
+ /** The project root the Python read as `Path.cwd()`. Defaults to the process's. */
45
+ cwd?: string;
46
+ timeoutMs?: number;
47
+ /** How the pasteable `registry prepare` is spelled in the notes. */
48
+ prepareCommand?: string;
49
+ }
50
+ export interface PrepareReport {
51
+ kind: "action" | "event";
52
+ /** The node type the overlay entry is stored under (the WAIT form for an event). */
53
+ nodeType: string;
54
+ connectionId: string;
55
+ /** The symbolic names written to `bindings.json`, when bindings were touched. */
56
+ bound?: {
57
+ connection: string;
58
+ folder: string;
59
+ };
60
+ /** Action path only. */
61
+ variants?: number;
62
+ inputFields?: number;
63
+ kept?: [kept: number, discarded: number];
64
+ objectName?: string;
65
+ }
66
+ /**
67
+ * `_match_catalog_object`: the catalog row `--object` names, or `undefined`
68
+ * when the catalog itself is unavailable — that failure belongs to expansion,
69
+ * whose message already covers it. Every refusal past the name rungs is
70
+ * retried once against a refreshed catalog before it is believed: the
71
+ * `uip is resources list` cache never invalidates itself (measured: 18
72
+ * objects stale vs 864 fresh on uipath-salesforce-sfdc). Ambiguity WITHIN a
73
+ * name rung is not retriable — the refusal's call, not this loop's.
74
+ */
75
+ export declare function matchCatalogObject(ctx: BuildContext, connectorKey: string, wanted: string, verb: string | undefined): Promise<CatalogueRow | undefined>;
76
+ /**
77
+ * The whole command. Throws a {@link Refusal} for every path the Python
78
+ * `sys.exit`ed on; the report is what a caller wanting more than the printed
79
+ * lines can read.
80
+ *
81
+ * When a `--resolve` reads a collection to the end on the connection this
82
+ * command PICKED and finds nothing, the other enabled connections for the
83
+ * connector are probed, and the run starts over pinned to the one that
84
+ * resolves everything (flow-builder-sdk#744). The Python re-exec'd itself for
85
+ * that; here the bindings snapshot is restored and `prepareConnector` is
86
+ * re-entered with `--connection-id <winner> --refresh-lookups`. The refresh is
87
+ * NOT optional: the ledger keys a resolution by `[nodeType, field, by, value]`
88
+ * and not by connection, so an id recorded against the connection just
89
+ * abandoned would come back as "already resolved" on the re-run.
90
+ */
91
+ export declare function prepareConnector(options: PrepareOptions, ports: PreparePorts): Promise<PrepareReport>;
@@ -0,0 +1,376 @@
1
+ /**
2
+ * `main()` of `prepare_connector.py`, as a function of its options and ports.
3
+ *
4
+ * Fetch ONE connector op's FULL, connection-resolved schema into the
5
+ * `./connectors-local/` overlay plus a typed `.ts`. The baked library is
6
+ * tenant-agnostic, so schema-dynamic ops ship only their connection-independent
7
+ * fields; this closes that at author time with a live connection, writing the
8
+ * same artifacts the bulk generator produces into an overlay the compile CLIs
9
+ * auto-detect. Calls ACCUMULATE — each prepared op merges into `--out`.
10
+ *
11
+ * The stages, in the Python's order: the connection (discovered or checked)
12
+ * and `bindings.json`; the registry definition, or the event twin; the schema
13
+ * (Generic expansion or a describe); the overlay merge, guarded by the
14
+ * keep-prepared-schema rule; the object decision and the lookup resolutions
15
+ * in the ledger; the descriptors; then the summary and every note, and finally
16
+ * the repointed import and the handoff.
17
+ *
18
+ * Every `uip` call goes through the {@link BuildContext} built from the ports,
19
+ * so a test drives the whole pipeline from a fake client; every `sys.exit` is a
20
+ * thrown {@link Refusal} carrying the same text (see `messages.ts`'s
21
+ * `exitText` for how the boundary spells them).
22
+ *
23
+ * Every path is printed as the author typed it — `--out` and `--bindings` go
24
+ * into the lines verbatim, as `args.out` and `args.bindings` did — while the
25
+ * file system is reached through paths resolved against `cwd`.
26
+ */
27
+ import { resolve } from "node:path";
28
+ import { PACKAGE_NAME } from "../../package-name.js";
29
+ import { afterLast } from "../compat/pystr.js";
30
+ import { extractCanonical, isHttpPassthrough, nodeOf } from "../library-build/canonical.js";
31
+ import { createBuildContext, isResourcesList, registryGet } from "../library-build/context.js";
32
+ import { enrichEntry } from "../library-build/enrich.js";
33
+ import { expandGenericForConnector, genericTemplatesByOp } from "../library-build/generic-expand.js";
34
+ import { planLibrary } from "../library-build/plan.js";
35
+ import { MemoryResponseCache } from "../uip/response-cache.js";
36
+ import { registryActions } from "./actions.js";
37
+ import { discoverConnection, lookupConnection, mergeBindings, restoreBindings, snapshotBindings, } from "./connections.js";
38
+ import { prepareEvent } from "./event.js";
39
+ import { descriptorUsage } from "./handoff.js";
40
+ import { ResolutionsExhausted, allParentsResolved, resolvedParentValues, writeResolutions } from "./ledger.js";
41
+ import { PREPARE_COMMAND, PrepareRefusal, bindingsLine, candidateLabel, connectionLine, generatedModulesLine, genericActionNeedsObjectMessage, inputFieldNote, keptSchemaMessage, lookupVocabularyLines, missingGenericSchemaMessage, missingParentsNote, nextLine, noCanonicalEntryMessage, objectFlagsOnlyForGenericMessage, objectNoteLine, objectRecordedLine, parentFieldNamesMismatchMessage, parentOnlyMessage, prefixed, preparedSummaryLine, rejectedParentFieldsMessage, rerunAgainstLine, resolvedParentsNote, tsNote, unresolvedActionMessage, } from "./messages.js";
42
+ import { ObjectMatchRefusal, RESOLUTIONS_FILENAME, matchObject, recordObjectResolution } from "./objects.js";
43
+ import { countInputFields, keepPreparedSchema, lookupSpecsFromOverlay, mergeFilesInto, parentFields as overlayParentFields, schemaActionParents, } from "./overlay.js";
44
+ import { declaredParents, objectActionRequest, objectActionSpecs, parseFields } from "./parents.js";
45
+ import { regenerateDescriptors } from "./regenerate.js";
46
+ import { retryOtherConnections } from "./retry.js";
47
+ import { repointSource } from "./source-import.js";
48
+ import { isPlainObject, pyGet, pyOr, pyPathJoin, pyPathlibStr, pyStrAny, pyTruthy } from "./support.js";
49
+ function memoryCaches() {
50
+ return { registry: new MemoryResponseCache(), is: new MemoryResponseCache(), connectors: new MemoryResponseCache() };
51
+ }
52
+ /**
53
+ * `_match_catalog_object`: the catalog row `--object` names, or `undefined`
54
+ * when the catalog itself is unavailable — that failure belongs to expansion,
55
+ * whose message already covers it. Every refusal past the name rungs is
56
+ * retried once against a refreshed catalog before it is believed: the
57
+ * `uip is resources list` cache never invalidates itself (measured: 18
58
+ * objects stale vs 864 fresh on uipath-salesforce-sfdc). Ambiguity WITHIN a
59
+ * name rung is not retriable — the refusal's call, not this loop's.
60
+ */
61
+ export async function matchCatalogObject(ctx, connectorKey, wanted, verb) {
62
+ let rows = ((await isResourcesList(ctx, connectorKey, { operation: verb })) ?? []).filter(isPlainObject);
63
+ if (rows.length === 0)
64
+ return undefined;
65
+ for (const attempt of ["cached", "refreshed"]) {
66
+ try {
67
+ const { row, note } = matchObject(rows, wanted, verb);
68
+ if (note)
69
+ ctx.reporter.info(objectNoteLine(note));
70
+ return row;
71
+ }
72
+ catch (error) {
73
+ if (!(error instanceof ObjectMatchRefusal))
74
+ throw error;
75
+ if (attempt === "cached" && error.retriable) {
76
+ const refreshed = ((await isResourcesList(ctx, connectorKey, { operation: verb, refresh: true })) ?? []).filter(isPlainObject);
77
+ if (refreshed.length > 0)
78
+ rows = refreshed;
79
+ continue;
80
+ }
81
+ throw error;
82
+ }
83
+ }
84
+ return undefined;
85
+ }
86
+ /** Stage 0: the connection, discovered or checked, and its row in `bindings.json`. */
87
+ async function connect(options, ports) {
88
+ const info = (line) => ports.reporter.info(line);
89
+ let row;
90
+ let connectionId;
91
+ if (!options.connectionId) {
92
+ // Discover the connection when the caller did not name one, and record it
93
+ // in bindings.json so the author never has to look up either key — the
94
+ // step that removes 4-7 tool calls per task.
95
+ row = await discoverConnection(ports.client, options.connectorKey, options.connection);
96
+ connectionId = pyStrAny(row.Id);
97
+ }
98
+ else {
99
+ // An explicit id gets the same gate discovery applies: a `State: Failed`
100
+ // connection answers field discovery with an EMPTY schema.
101
+ connectionId = options.connectionId;
102
+ row = await lookupConnection(ports.client, options.connectorKey, connectionId);
103
+ }
104
+ info(connectionLine(row, connectionId));
105
+ if (options.noBindings)
106
+ return { connectionId, row };
107
+ // Recorded on BOTH routes. Until 3.30.5 only discovery wrote it, and the
108
+ // explicit-id route left the author hand-writing the id and folder key.
109
+ const bindingsShown = options.bindings ?? "./bindings.json";
110
+ const bindingsPath = resolve(ports.cwd ?? process.cwd(), bindingsShown);
111
+ // Taken before the first write so a later refusal can undo exactly this
112
+ // command's changes, and only them.
113
+ const rollback = { path: bindingsPath, snapshot: snapshotBindings(bindingsPath), shown: bindingsShown };
114
+ // `args.bind_connection or args.key.rsplit("-", 1)[-1]`: an empty
115
+ // --bind-connection falls back, as Python's `or` did. --bind-folder is an
116
+ // argparse default, so an empty one STANDS, as it did there.
117
+ const symbolic = pyOr(options.bindConnection, afterLast(options.connectorKey, "-"));
118
+ const folder = options.bindFolder ?? "shared";
119
+ const [wroteConnection, wroteFolder] = mergeBindings(bindingsPath, symbolic, folder, row);
120
+ if (wroteConnection)
121
+ info(bindingsLine(symbolic, bindingsShown));
122
+ if (wroteFolder)
123
+ info(bindingsLine(folder, bindingsShown));
124
+ return { connectionId, row, bound: { connection: symbolic, folder }, rollback };
125
+ }
126
+ /**
127
+ * The whole command. Throws a {@link Refusal} for every path the Python
128
+ * `sys.exit`ed on; the report is what a caller wanting more than the printed
129
+ * lines can read.
130
+ *
131
+ * When a `--resolve` reads a collection to the end on the connection this
132
+ * command PICKED and finds nothing, the other enabled connections for the
133
+ * connector are probed, and the run starts over pinned to the one that
134
+ * resolves everything (flow-builder-sdk#744). The Python re-exec'd itself for
135
+ * that; here the bindings snapshot is restored and `prepareConnector` is
136
+ * re-entered with `--connection-id <winner> --refresh-lookups`. The refresh is
137
+ * NOT optional: the ledger keys a resolution by `[nodeType, field, by, value]`
138
+ * and not by connection, so an id recorded against the connection just
139
+ * abandoned would come back as "already resolved" on the re-run.
140
+ */
141
+ export async function prepareConnector(options, ports) {
142
+ const info = (line) => ports.reporter.info(line);
143
+ const warn = (line) => ports.reporter.warn(line);
144
+ // Whether the CALLER chose the connection, recorded before discovery answers
145
+ // with its own. An explicit choice is never second-guessed: the retry below
146
+ // is for a connection this command picked, not for one the author named.
147
+ const pinned = pyTruthy(options.connectionId) || pyTruthy(options.connection);
148
+ const connected = await connect(options, ports);
149
+ try {
150
+ return await prepareOnConnection(options, ports, connected);
151
+ }
152
+ catch (error) {
153
+ if (!(error instanceof ResolutionsExhausted))
154
+ throw error;
155
+ // The collection was read to the END on this connection and the value is
156
+ // not in it. That is evidence about the CONNECTION, not only about the
157
+ // value — so before failing, try the other enabled connections. A
158
+ // transport failure is the parent refusal and never reaches here.
159
+ const chosen = await retryOtherConnections({
160
+ client: ports.client,
161
+ reporter: ports.reporter,
162
+ connectorKey: options.connectorKey,
163
+ connectionId: connected.connectionId,
164
+ connection: options.connection,
165
+ pinned,
166
+ }, error.plan, error.first);
167
+ // Undo the bindings this run wrote for the connection that cannot serve
168
+ // the lookups, then start over pinned to the one that can. Re-running
169
+ // rather than switching in place is deliberate: the overlay and its
170
+ // lookup specs are described THROUGH a connection
171
+ // (`lookupSpecsFromOverlay`), so adopting a different connection after the
172
+ // describe would leave the overlay describing one connection while
173
+ // bindings.json names another.
174
+ if (connected.rollback)
175
+ restoreBindings(connected.rollback.path, connected.rollback.snapshot, warn, connected.rollback.shown);
176
+ const chosenId = pyStrAny(pyGet(chosen, "Id", null));
177
+ info(rerunAgainstLine(candidateLabel(chosen), error.field, chosenId));
178
+ // THE LOOP GUARD, and it is this line rather than a counter: the re-entry
179
+ // carries `connectionId`, so its own `pinned` is true and a second
180
+ // exhaustion takes the pinned branch — a refusal naming the alternatives —
181
+ // instead of probing again. The Python got the same guard from the same
182
+ // place, since the re-exec'd process recomputed
183
+ // `args._connection_pinned = bool(args.connection_id or args.connection)`
184
+ // from the `--connection-id` it had just been handed. One probing round
185
+ // per command is the whole contract: the probe has already proved this
186
+ // connection resolves every lookup, so a re-run that still cannot is a
187
+ // changed tenant, not another connection to go looking through.
188
+ return prepareConnector({ ...options, connectionId: chosenId, refreshLookups: true }, ports);
189
+ }
190
+ }
191
+ /** Everything after stage 0, against one settled connection. */
192
+ async function prepareOnConnection(options, ports, connected) {
193
+ const cwd = ports.cwd ?? process.cwd();
194
+ const info = (line) => ports.reporter.info(line);
195
+ const warn = (line) => ports.reporter.warn(line);
196
+ const command = ports.prepareCommand ?? PREPARE_COMMAND;
197
+ const { connectorKey, action } = options;
198
+ const fieldPairs = options.fields ?? [];
199
+ const parentFields = parseFields(fieldPairs);
200
+ const outShown = options.out ?? "./connectors-local";
201
+ const out = resolve(cwd, outShown);
202
+ const importSpecifier = options.importSpecifier ?? PACKAGE_NAME;
203
+ const jsonOnly = options.jsonOnly ?? false;
204
+ const { connectionId, bound, rollback } = connected;
205
+ const ctx = createBuildContext({ client: ports.client, caches: ports.caches ?? memoryCaches(), reporter: ports.reporter, concurrency: 1, timeoutMs: ports.timeoutMs }, { connectionId, parentFields });
206
+ const nodeType = `uipath.connector.${connectorKey}.${action}`;
207
+ const cacheName = await registryGet(ctx, nodeType, true);
208
+ if (cacheName === undefined) {
209
+ // Not an activity. Connector EVENTS live one namespace over, and their
210
+ // registry definition only answers with a connection, which this command
211
+ // has by now. Same loop, different twin pair.
212
+ const event = await prepareEvent(ctx, {
213
+ connectorKey,
214
+ action,
215
+ connectionId,
216
+ objectName: options.objectName,
217
+ allObjects: options.allObjects,
218
+ fields: fieldPairs,
219
+ resolve: options.resolve,
220
+ refreshLookups: options.refreshLookups,
221
+ out,
222
+ outShown,
223
+ importSpecifier,
224
+ jsonOnly,
225
+ boundConnection: bound?.connection,
226
+ boundFolder: bound?.folder,
227
+ bindings: rollback,
228
+ prepareCommand: command,
229
+ });
230
+ if (event !== undefined) {
231
+ return { kind: "event", nodeType: event.eventNodeType, connectionId, bound, objectName: event.objectName };
232
+ }
233
+ const actions = await registryActions(ports.client, connectorKey, ports.timeoutMs);
234
+ throw new PrepareRefusal(unresolvedActionMessage(connectorKey, action, nodeType, actions), "ACTION_UNKNOWN");
235
+ }
236
+ const payload = ctx.caches.registry.read(cacheName);
237
+ // The registry's own declaration of parent inputs, read from the same reply.
238
+ const declared = declaredParents(payload);
239
+ let entry = extractCanonical(nodeOf(payload));
240
+ if (entry === undefined)
241
+ throw new PrepareRefusal(noCanonicalEntryMessage(nodeType), "NO_CANONICAL_ENTRY");
242
+ if (options.version)
243
+ entry.version = options.version;
244
+ if (parentFields.size > 0) {
245
+ const request = objectActionRequest(payload, parentFields);
246
+ if (request === undefined) {
247
+ throw new PrepareRefusal(parentFieldNamesMismatchMessage([...parentFields.keys()], objectActionSpecs(payload)), "PARENT_FIELDS_MISMATCH");
248
+ }
249
+ entry.operation.customFieldsRequestDetails = request;
250
+ }
251
+ let objectName = options.objectName;
252
+ let objectDecision;
253
+ let preparedEntries;
254
+ const isExpandableGeneric = entry.operation.activityType === "Generic" && !isHttpPassthrough(entry);
255
+ if (isExpandableGeneric) {
256
+ if (!objectName && !options.allObjects)
257
+ throw new PrepareRefusal(genericActionNeedsObjectMessage(), "OBJECT_REQUIRED");
258
+ const templates = genericTemplatesByOp([entry]).get(connectorKey) ?? new Map();
259
+ if (objectName) {
260
+ // The author's name, not necessarily the API's: matched deterministically
261
+ // BEFORE expansion — expansion re-reads the same cached catalog, so the
262
+ // match costs no extra network.
263
+ const verb = templates.size === 1 ? [...templates.keys()][0] : undefined;
264
+ const requested = objectName;
265
+ const row = await matchCatalogObject(ctx, connectorKey, objectName, verb);
266
+ if (row !== undefined) {
267
+ objectName = pyStrAny(pyOr(pyGet(row, "Name", null), objectName));
268
+ objectDecision = { requested, row, verb };
269
+ }
270
+ }
271
+ const selected = options.allObjects ? undefined : [objectName];
272
+ preparedEntries = await expandGenericForConnector(ctx, connectorKey, templates, selected);
273
+ if (preparedEntries.length === 0) {
274
+ const operation = pyStrAny(pyOr(pyGet(entry.operation, "name", null), action));
275
+ throw new PrepareRefusal(missingGenericSchemaMessage(operation, options.allObjects ? undefined : objectName), "GENERIC_SCHEMA_MISSING");
276
+ }
277
+ }
278
+ else {
279
+ if (objectName || options.allObjects)
280
+ throw new PrepareRefusal(objectFlagsOnlyForGenericMessage(), "OBJECT_NOT_GENERIC");
281
+ entry = await enrichEntry(ctx, entry); // full schema via --connection-id
282
+ preparedEntries = [entry];
283
+ }
284
+ const entryNodeType = entry.nodeType;
285
+ const plan = planLibrary(preparedEntries, (requestedNodeType) => (requestedNodeType === entryNodeType ? nodeOf(payload) : undefined));
286
+ for (const line of plan.warnings)
287
+ warn(line);
288
+ const kept = keepPreparedSchema(out, entryNodeType, plan.files, parentFields, objectName);
289
+ if (kept === undefined)
290
+ mergeFilesInto(plan.files, out);
291
+ // The object decision is the FIRST resolution — recorded before any lookup
292
+ // rows, because it is their prerequisite.
293
+ if (objectDecision !== undefined) {
294
+ recordObjectResolution(out, nodeType, objectDecision.requested, objectDecision.row, objectDecision.verb);
295
+ // Named as the author spelled `--out` (`os.path.join(args.out, …)`).
296
+ info(objectRecordedLine(objectDecision.requested, objectName, pyPathJoin(outShown, RESOLUTIONS_FILENAME)));
297
+ }
298
+ if (pyTruthy(options.resolve)) {
299
+ // A `ResolutionsExhausted` propagates to `prepareConnector`, which owns
300
+ // the retry: re-running pinned means starting the whole command over.
301
+ await writeResolutions({
302
+ client: ports.client,
303
+ connectorKey,
304
+ connectionId,
305
+ out,
306
+ outShown,
307
+ nodeType,
308
+ objectName,
309
+ resolve: options.resolve,
310
+ refreshLookups: options.refreshLookups,
311
+ reporter: ports.reporter,
312
+ });
313
+ }
314
+ const modules = regenerateDescriptors(out, importSpecifier, jsonOnly);
315
+ // The generator's own last line, which the Python spawned and so printed
316
+ // between the resolution lines and the summary; under --json-only it never
317
+ // ran and said nothing.
318
+ if (!jsonOnly)
319
+ info(generatedModulesLine(modules.length, pyPathlibStr(outShown)));
320
+ const inputFields = countInputFields(out, entryNodeType, objectName);
321
+ const variants = preparedEntries.length;
322
+ // The describe is the evidence, not the finished field count: a rejected
323
+ // parent set leaves the registry-DECLARED fields in the overlay, so surface
324
+ // the CLI's own message instead of that quiet success.
325
+ const failures = ctx.failedFieldDescribes;
326
+ if (fieldPairs.length > 0 && (failures.length > 0 || inputFields === 0)) {
327
+ throw new PrepareRefusal(rejectedParentFieldsMessage(fieldPairs, failures), "PARENT_FIELDS_REJECTED");
328
+ }
329
+ info(preparedSummaryLine(nodeType, outShown, tsNote(jsonOnly, connectorKey), variants, inputFieldNote(inputFields)));
330
+ if (kept !== undefined)
331
+ info(keptSchemaMessage(action, kept[0], kept[1]));
332
+ for (const line of lookupVocabularyLines(connectorKey, action, objectName, lookupSpecsFromOverlay(out, nodeType, objectName), command)) {
333
+ info(line);
334
+ }
335
+ // Whether this operation has parent fields is answered by what was just
336
+ // prepared, not by a catalog flag.
337
+ const [parents, parentOnly] = overlayParentFields(out, entryNodeType, objectName);
338
+ if (parentOnly && fieldPairs.length > 0) {
339
+ throw new PrepareRefusal(parentOnlyMessage(parents, fieldPairs), "PARENT_VALUES_UNRESOLVED");
340
+ }
341
+ // Whether the schema action RAN is decided by its inputs, not by its output:
342
+ // every parent it names must have arrived as `-f`. Union of both declaration
343
+ // sites so an overlay that omits `schemaAction` still gets the registry's.
344
+ const actionParents = schemaActionParents(out, entryNodeType, objectName);
345
+ for (const name of declared)
346
+ if (!actionParents.includes(name))
347
+ actionParents.push(name);
348
+ const missing = actionParents.filter((name) => !parentFields.has(name));
349
+ // Silent when the schema was KEPT: the note's premise is that the overlay
350
+ // carries only the unresolved entry, and it does not.
351
+ if (missing.length > 0 && kept === undefined) {
352
+ const resolvedParents = resolvedParentValues(out, nodeType, actionParents);
353
+ if (allParentsResolved(actionParents, resolvedParents)) {
354
+ warn(resolvedParentsNote(connectorKey, action, actionParents, resolvedParents, command));
355
+ }
356
+ else {
357
+ warn(missingParentsNote(connectorKey, action, actionParents, missing, parentFields, command));
358
+ }
359
+ }
360
+ if (!jsonOnly) {
361
+ // Print what was bound, so the last line of output is a call the reader
362
+ // can paste rather than `<binding-name>` placeholders. `or`, not `??`: an
363
+ // empty symbolic name is a placeholder in Python's eyes too.
364
+ let usage = descriptorUsage(outShown, connectorKey, pyOr(bound?.connection, "<binding-name>"), pyOr(bound?.folder, "<folder-binding-name>"), cwd);
365
+ const repointed = repointSource({ out: outShown, connectorKey, cwd, source: options.source, noSourceRewrite: options.noSourceRewrite });
366
+ if (repointed.length > 0 && repointed[0].startsWith("repointed ")) {
367
+ // The edit is DONE, so telling the author to make it is now false.
368
+ usage = usage.filter((line) => !line.startsWith("import {"));
369
+ }
370
+ for (const line of repointed)
371
+ info(prefixed(line));
372
+ for (const line of usage)
373
+ info(nextLine(line));
374
+ }
375
+ return { kind: "action", nodeType, connectionId, bound, variants, inputFields, kept, objectName };
376
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Write `<out>/<connectorKey>.ts` for every connector in the overlay and
3
+ * return the module names written; nothing at all under `--json-only`.
4
+ *
5
+ * The generator wrote every module and only then exited 1 on a required-input
6
+ * gap; the files are on disk here too, and the failure is as loud and as late
7
+ * (a {@link Refusal} carrying the generator's own text).
8
+ */
9
+ export declare function regenerateDescriptors(out: string, importSpecifier: string, jsonOnly?: boolean): string[];
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Rewrite the overlay's typed descriptors from the overlay's own JSON.
3
+ *
4
+ * Both prepare paths end here. The EVENT path used not to: it wrote the JSON
5
+ * overlay and returned, so a project whose only prepare was an event got no
6
+ * `.ts` at all, and one that had prepared an action earlier kept that older
7
+ * run's module — generated before the event's parameters were in the overlay,
8
+ * so `where` was `Record<string, string>` and the trigger carried no
9
+ * `lookups`. That is the module `prepare` tells the author to import, and
10
+ * `--refresh-lookups` could not repair it.
11
+ *
12
+ * `includeGenericExpanded` is decided from the WHOLE overlay index rather than
13
+ * the entries of this run: the generator rewrites every module under the
14
+ * output, so reading one run would drop the descriptors an earlier
15
+ * `GenericExpanded` prepare had written.
16
+ *
17
+ * Ported from `_regenerate_descriptors`, which spawned
18
+ * `generate_connectors_ts.py --library <out> --output <out>`; the generator is
19
+ * now `renderDescriptorModules`, called in-process.
20
+ */
21
+ import { mkdirSync, writeFileSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { Refusal } from "../errors.js";
24
+ import { formatRequiredInputGaps, renderDescriptorModules } from "../generators/descriptors.js";
25
+ import { loadLibrary } from "../library-reader.js";
26
+ import { overlayHasGenericExpanded } from "./overlay.js";
27
+ /**
28
+ * Write `<out>/<connectorKey>.ts` for every connector in the overlay and
29
+ * return the module names written; nothing at all under `--json-only`.
30
+ *
31
+ * The generator wrote every module and only then exited 1 on a required-input
32
+ * gap; the files are on disk here too, and the failure is as loud and as late
33
+ * (a {@link Refusal} carrying the generator's own text).
34
+ */
35
+ export function regenerateDescriptors(out, importSpecifier, jsonOnly = false) {
36
+ if (jsonOnly)
37
+ return [];
38
+ const library = loadLibrary(out);
39
+ const output = renderDescriptorModules(library, {
40
+ importSpecifier,
41
+ includeGenericExpanded: overlayHasGenericExpanded(out),
42
+ });
43
+ mkdirSync(out, { recursive: true });
44
+ for (const [name, text] of output.modules)
45
+ writeFileSync(join(out, name), text, "utf8");
46
+ if (output.requiredInputGaps.length > 0) {
47
+ throw new Refusal(formatRequiredInputGaps(output.requiredInputGaps), "REQUIRED_INPUT_GAP");
48
+ }
49
+ return [...output.modules.keys()];
50
+ }