@uipath/maestro-builder-sdk 5.2.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 (238) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -0
  3. package/dist/bindings-v2.d.ts +37 -0
  4. package/dist/bindings-v2.js +155 -0
  5. package/dist/bindings.d.ts +6 -0
  6. package/dist/bindings.js +6 -0
  7. package/dist/bpmn/bpmn-expr-check.d.ts +41 -0
  8. package/dist/bpmn/bpmn-expr-check.js +218 -0
  9. package/dist/bpmn/bpmn-sdk.d.ts +2257 -0
  10. package/dist/bpmn/bpmn-sdk.js +1476 -0
  11. package/dist/bpmn/check-cli.d.ts +3 -0
  12. package/dist/bpmn/check-cli.js +32 -0
  13. package/dist/bpmn/check.d.ts +25 -0
  14. package/dist/bpmn/check.js +430 -0
  15. package/dist/bpmn/compile-cli.d.ts +3 -0
  16. package/dist/bpmn/compile-cli.js +60 -0
  17. package/dist/bpmn/connector.d.ts +56 -0
  18. package/dist/bpmn/connector.js +199 -0
  19. package/dist/bpmn/decompile-cli.d.ts +8 -0
  20. package/dist/bpmn/decompile-cli.js +54 -0
  21. package/dist/bpmn/decompile.d.ts +6 -0
  22. package/dist/bpmn/decompile.js +1108 -0
  23. package/dist/bpmn/format-profile.d.ts +27 -0
  24. package/dist/bpmn/format-profile.js +11 -0
  25. package/dist/bpmn/intsvc.d.ts +77 -0
  26. package/dist/bpmn/intsvc.js +155 -0
  27. package/dist/bpmn/load.d.ts +4 -0
  28. package/dist/bpmn/load.js +22 -0
  29. package/dist/bpmn/merge-cli.d.ts +3 -0
  30. package/dist/bpmn/merge-cli.js +45 -0
  31. package/dist/bpmn/merge.d.ts +19 -0
  32. package/dist/bpmn/merge.js +293 -0
  33. package/dist/bpmn/registry-types.json +1869 -0
  34. package/dist/bpmn/serialize.d.ts +28 -0
  35. package/dist/bpmn/serialize.js +757 -0
  36. package/dist/bpmn/tidy-cli.d.ts +2 -0
  37. package/dist/bpmn/tidy-cli.js +39 -0
  38. package/dist/bpmn/typed-node.d.ts +382 -0
  39. package/dist/bpmn/typed-node.js +551 -0
  40. package/dist/bpmn/uipath-moddle.v1.json +823 -0
  41. package/dist/bpmn/xml-ranges.d.ts +45 -0
  42. package/dist/bpmn/xml-ranges.js +151 -0
  43. package/dist/case/case-expr-check.d.ts +35 -0
  44. package/dist/case/case-expr-check.js +85 -0
  45. package/dist/case/case-sdk.d.ts +1282 -0
  46. package/dist/case/case-sdk.js +923 -0
  47. package/dist/case/check-cli.d.ts +3 -0
  48. package/dist/case/check-cli.js +31 -0
  49. package/dist/case/check.d.ts +18 -0
  50. package/dist/case/check.js +456 -0
  51. package/dist/case/compile-cli.d.ts +3 -0
  52. package/dist/case/compile-cli.js +291 -0
  53. package/dist/case/decompile-cli.d.ts +9 -0
  54. package/dist/case/decompile-cli.js +117 -0
  55. package/dist/case/decompile.d.ts +187 -0
  56. package/dist/case/decompile.js +1170 -0
  57. package/dist/case/entry-points.d.ts +79 -0
  58. package/dist/case/entry-points.js +118 -0
  59. package/dist/case/format-profile.d.ts +60 -0
  60. package/dist/case/format-profile.js +79 -0
  61. package/dist/case/ids.d.ts +24 -0
  62. package/dist/case/ids.js +76 -0
  63. package/dist/case/load.d.ts +12 -0
  64. package/dist/case/load.js +32 -0
  65. package/dist/case/preserve.d.ts +133 -0
  66. package/dist/case/preserve.js +105 -0
  67. package/dist/case/serialize.d.ts +10 -0
  68. package/dist/case/serialize.js +1414 -0
  69. package/dist/check-cli.d.ts +3 -0
  70. package/dist/check-cli.js +118 -0
  71. package/dist/check.d.ts +146 -0
  72. package/dist/check.js +4898 -0
  73. package/dist/cli/commands/bpmn.d.ts +2 -0
  74. package/dist/cli/commands/bpmn.js +73 -0
  75. package/dist/cli/commands/case.d.ts +2 -0
  76. package/dist/cli/commands/case.js +60 -0
  77. package/dist/cli/commands/flow.d.ts +2 -0
  78. package/dist/cli/commands/flow.js +99 -0
  79. package/dist/cli/commands/registry.d.ts +10 -0
  80. package/dist/cli/commands/registry.js +170 -0
  81. package/dist/cli/common.d.ts +30 -0
  82. package/dist/cli/common.js +92 -0
  83. package/dist/cli/index.d.ts +2 -0
  84. package/dist/cli/index.js +18 -0
  85. package/dist/cli-run.d.ts +2 -0
  86. package/dist/cli-run.js +42 -0
  87. package/dist/compile-cli.d.ts +3 -0
  88. package/dist/compile-cli.js +160 -0
  89. package/dist/config.d.ts +47 -0
  90. package/dist/config.js +201 -0
  91. package/dist/core/actions.d.ts +3244 -0
  92. package/dist/core/actions.js +1062 -0
  93. package/dist/core/binding-messages.d.ts +1 -0
  94. package/dist/core/binding-messages.js +16 -0
  95. package/dist/core/bindings.d.ts +12 -0
  96. package/dist/core/bindings.js +67 -0
  97. package/dist/core/ceql.d.ts +73 -0
  98. package/dist/core/ceql.js +272 -0
  99. package/dist/core/cli-spelling.d.ts +39 -0
  100. package/dist/core/cli-spelling.js +62 -0
  101. package/dist/core/connector-raw-node.d.ts +21 -0
  102. package/dist/core/connector-raw-node.js +47 -0
  103. package/dist/core/connectors.d.ts +184 -0
  104. package/dist/core/connectors.js +128 -0
  105. package/dist/core/expr-check.d.ts +93 -0
  106. package/dist/core/expr-check.js +186 -0
  107. package/dist/core/expr.d.ts +323 -0
  108. package/dist/core/expr.js +400 -0
  109. package/dist/core/index.d.ts +10 -0
  110. package/dist/core/index.js +10 -0
  111. package/dist/core/library.d.ts +440 -0
  112. package/dist/core/library.js +1183 -0
  113. package/dist/core/list-envelope.d.ts +45 -0
  114. package/dist/core/list-envelope.js +97 -0
  115. package/dist/core/lookup-store.d.ts +22 -0
  116. package/dist/core/lookup-store.js +85 -0
  117. package/dist/core/lookups.d.ts +227 -0
  118. package/dist/core/lookups.js +231 -0
  119. package/dist/core/node-classes.d.ts +234 -0
  120. package/dist/core/node-classes.js +158 -0
  121. package/dist/core/script-return.d.ts +68 -0
  122. package/dist/core/script-return.js +197 -0
  123. package/dist/core/stable-id.d.ts +28 -0
  124. package/dist/core/stable-id.js +37 -0
  125. package/dist/core-definitions.json +16249 -0
  126. package/dist/decompile-cli.d.ts +3 -0
  127. package/dist/decompile-cli.js +131 -0
  128. package/dist/decompile.d.ts +138 -0
  129. package/dist/decompile.js +2482 -0
  130. package/dist/emit.d.ts +10 -0
  131. package/dist/emit.js +60 -0
  132. package/dist/event-filters.d.ts +130 -0
  133. package/dist/event-filters.js +137 -0
  134. package/dist/flow-expr-check.d.ts +17 -0
  135. package/dist/flow-expr-check.js +193 -0
  136. package/dist/flow-sdk.d.ts +1341 -0
  137. package/dist/flow-sdk.js +1164 -0
  138. package/dist/flow-variables.d.ts +13 -0
  139. package/dist/flow-variables.js +42 -0
  140. package/dist/format-profile.d.ts +72 -0
  141. package/dist/format-profile.js +97 -0
  142. package/dist/generators/_connections.py +287 -0
  143. package/dist/generators/_events.py +355 -0
  144. package/dist/generators/_lookups.py +114 -0
  145. package/dist/generators/_naming.py +185 -0
  146. package/dist/generators/_objects.py +299 -0
  147. package/dist/generators/_resolve.py +273 -0
  148. package/dist/generators/convert_library_to_md.py +1441 -0
  149. package/dist/generators/extract_library.py +125 -0
  150. package/dist/generators/generate_connectors_ts.py +936 -0
  151. package/dist/generators/generate_library_json.py +2527 -0
  152. package/dist/generators/generate_triggers_ts.py +110 -0
  153. package/dist/generators/materialize_registry.py +155 -0
  154. package/dist/generators/prepare_connector.py +1688 -0
  155. package/dist/index.d.ts +35 -0
  156. package/dist/index.js +35 -0
  157. package/dist/ixp-definition.json +1982 -0
  158. package/dist/library.d.ts +6 -0
  159. package/dist/library.js +6 -0
  160. package/dist/load.d.ts +16 -0
  161. package/dist/load.js +95 -0
  162. package/dist/merge-cli.d.ts +3 -0
  163. package/dist/merge-cli.js +47 -0
  164. package/dist/merge.d.ts +125 -0
  165. package/dist/merge.js +0 -0
  166. package/dist/migrate.d.ts +15 -0
  167. package/dist/migrate.js +245 -0
  168. package/dist/node-runtime.d.ts +3 -0
  169. package/dist/node-runtime.js +22 -0
  170. package/dist/package-name.d.ts +17 -0
  171. package/dist/package-name.js +17 -0
  172. package/dist/ref-resolve.d.ts +77 -0
  173. package/dist/ref-resolve.js +170 -0
  174. package/dist/registry/cache.d.ts +55 -0
  175. package/dist/registry/cache.js +134 -0
  176. package/dist/registry/curated-overlay.d.ts +16 -0
  177. package/dist/registry/curated-overlay.js +62 -0
  178. package/dist/registry/extractor.d.ts +22 -0
  179. package/dist/registry/extractor.js +18 -0
  180. package/dist/registry/materialize-bin.d.ts +2 -0
  181. package/dist/registry/materialize-bin.js +7 -0
  182. package/dist/registry/materialize-cli.d.ts +1 -0
  183. package/dist/registry/materialize-cli.js +46 -0
  184. package/dist/registry/materializer.d.ts +23 -0
  185. package/dist/registry/materializer.js +34 -0
  186. package/dist/registry/path-cli.d.ts +1 -0
  187. package/dist/registry/path-cli.js +56 -0
  188. package/dist/registry/prepare-cli.d.ts +62 -0
  189. package/dist/registry/prepare-cli.js +185 -0
  190. package/dist/registry/pull-cli.d.ts +1 -0
  191. package/dist/registry/pull-cli.js +274 -0
  192. package/dist/registry/python.d.ts +26 -0
  193. package/dist/registry/python.js +46 -0
  194. package/dist/registry/search-cli.d.ts +52 -0
  195. package/dist/registry/search-cli.js +159 -0
  196. package/dist/schema-version.d.ts +165 -0
  197. package/dist/schema-version.js +148 -0
  198. package/dist/serialize.d.ts +64 -0
  199. package/dist/serialize.js +6398 -0
  200. package/lib/README.md +112 -0
  201. package/lib/library-json.samples/index.json +158 -0
  202. package/lib/library-json.samples/invariant-collections.json +83 -0
  203. package/lib/library-json.samples/list-envelopes.json +123 -0
  204. package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.json +131 -0
  205. package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.v1def.json +306 -0
  206. package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.json +86 -0
  207. package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.v1def.json +208 -0
  208. package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.json +2040 -0
  209. package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.v1def.json +195 -0
  210. package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.json +169 -0
  211. package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.v1def.json +209 -0
  212. package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.json +63 -0
  213. package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.v1def.json +262 -0
  214. package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.json +63 -0
  215. package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.v1def.json +213 -0
  216. package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.json +227 -0
  217. package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.v1def.json +373 -0
  218. package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.json +116 -0
  219. package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.v1def.json +369 -0
  220. package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.json +56 -0
  221. package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.v1def.json +256 -0
  222. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.json +116 -0
  223. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.v1def.json +320 -0
  224. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.json +56 -0
  225. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.v1def.json +207 -0
  226. package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.json +107 -0
  227. package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.v1def.json +264 -0
  228. package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.json +142 -0
  229. package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.v1def.json +306 -0
  230. package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.json +107 -0
  231. package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.v1def.json +217 -0
  232. package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.json +85 -0
  233. package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.v1def.json +209 -0
  234. package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.json +755 -0
  235. package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.v1def.json +513 -0
  236. package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.json +122 -0
  237. package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.v1def.json +227 -0
  238. package/package.json +85 -0
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * compile-cli — <Name>.case.ts → caseplan.json
4
+ *
5
+ * Usage:
6
+ * node --experimental-strip-types compile-cli.js <case.ts | BaseName> [-o out.json]
7
+ *
8
+ * Runs the fast static check first; if it passes, serializes to a V30
9
+ * caseplan.json. The authoritative deploy gate is `uip maestro case validate`.
10
+ * Output defaults to `caseplan.json` (the platform's canonical file name).
11
+ */
12
+ import { writeFileSync, readFileSync, existsSync } from 'node:fs';
13
+ import { join, dirname, basename } from 'node:path';
14
+ import { createHash } from 'node:crypto';
15
+ import { resolveCaseFile, loadBuiltCase } from './load.js';
16
+ import { serialize } from './serialize.js';
17
+ import { check } from './check.js';
18
+ import { entryPointIO } from './entry-points.js';
19
+ import { Library } from '../core/library.js';
20
+ import { Bindings } from '../core/bindings.js';
21
+ import { resolveLibraryDir } from '../registry/cache.js';
22
+ import { runWhenInvokedDirectly } from '../cli-run.js';
23
+ import { ensureTypeScriptRuntime } from '../node-runtime.js';
24
+ import { CASE_FORMAT_PROFILE } from './format-profile.js';
25
+ function opt(argv, name) {
26
+ const i = argv.indexOf(name);
27
+ return i >= 0 ? argv[i + 1] : undefined;
28
+ }
29
+ export async function run(argv) {
30
+ if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
31
+ console.error('usage: compile <case.ts | BaseName> [-o caseplan.json]');
32
+ return 2;
33
+ }
34
+ const flags = new Set(['-o', '--library', '--bindings', '--connectors-local']);
35
+ const pos = argv.find((a, i) => !flags.has(a) && !flags.has(argv[i - 1]));
36
+ if (!pos) {
37
+ console.error('compile: missing <case.ts | BaseName>');
38
+ return 2;
39
+ }
40
+ const file = resolveCaseFile(pos);
41
+ ensureTypeScriptRuntime();
42
+ const built = await loadBuiltCase(file);
43
+ const diags = check(built);
44
+ for (const d of diags)
45
+ console.error(` ${d.level === 'error' ? '✗' : '⚠'} [${d.code}] ${d.message}`);
46
+ const errors = diags.filter((d) => d.level === 'error');
47
+ if (errors.length) {
48
+ console.error(`compile: ${errors.length} error(s); not emitting.`);
49
+ return 1;
50
+ }
51
+ // Connector tasks resolve against the library; load it only when present, and
52
+ // bindings.json from alongside the case when present. Resolved through the same
53
+ // helper Flow and BPMN use, so `registry pull` serves all three families —
54
+ // reading the env directly skipped the shared cache, and a Case that compiled
55
+ // fine right after a pull on Flow failed here for no visible reason.
56
+ const libDir = resolveLibraryDir(opt(argv, '--library'));
57
+ // A `prepare-connector` overlay, auto-detected next to the case (like bindings.json).
58
+ const overlayDir = opt(argv, '--connectors-local')
59
+ ?? (existsSync(join('connectors-local', 'index.json')) ? 'connectors-local' : undefined);
60
+ const library = libDir && existsSync(join(libDir, 'index.json')) ? new Library(libDir, { overlayDir }) : undefined;
61
+ const bindFile = opt(argv, '--bindings') ?? (existsSync('bindings.json') ? 'bindings.json' : undefined);
62
+ const bindings = new Bindings(bindFile);
63
+ const caseplan = serialize(built, { library, bindings });
64
+ const out = opt(argv, '-o') ?? 'caseplan.json';
65
+ writeFileSync(out, JSON.stringify(caseplan, null, 2) + '\n');
66
+ const stages = caseplan.nodes.filter((n) => String(n.type).endsWith('Stage')).length;
67
+ const triggers = syncEntryPoints(caseplan, out);
68
+ const epNote = triggers >= 0 ? `, synced entry-points.json (${triggers} trigger(s))` : '';
69
+ const resources = syncBindingsV2(caseplan, out);
70
+ const bindingsNote = resources >= 0 ? `, synced bindings_v2.json (${resources} resource(s))` : '';
71
+ console.log(`compile: wrote ${out} (${stages} stage(s))${epNote}${bindingsNote}`);
72
+ return 0;
73
+ }
74
+ /**
75
+ * The name of the case file THE PACKAGE SHIPS, which is what an entry point's
76
+ * `filePath` has to name — not the name this compile happened to write.
77
+ *
78
+ * These diverge on the documented brownfield loop. `case decompile` generates a
79
+ * pipeline that compiles to `<Name>.caseplan.json` and then merges into the
80
+ * project's `caseplan.json`, so a `basename(outPath)` entry point pointed at
81
+ * `/content/LinearThreeStages.caseplan.json.bpmn` — a file no package contains,
82
+ * because the packaged pair is `caseplan.json` + `caseplan.json.bpmn`. The eval
83
+ * task that took that path never left `Pending (0/0 elements completed)`: the
84
+ * debug instance was created and no element ever started.
85
+ *
86
+ * `package-descriptor.json` is the project's own declaration of what it ships
87
+ * and `uip maestro case init` writes it beside `entry-points.json`, so it is the
88
+ * authority whenever it is there.
89
+ */
90
+ function packagedCaseFileName(dir, outPath) {
91
+ const descriptorPath = join(dir, 'package-descriptor.json');
92
+ if (existsSync(descriptorPath)) {
93
+ try {
94
+ const files = JSON.parse(readFileSync(descriptorPath, 'utf8'))?.files;
95
+ if (files && typeof files === 'object') {
96
+ // The descriptor keys the pair by logical name; the case file is the one
97
+ // whose BPMN sibling it also ships.
98
+ const named = Object.keys(files).find((k) => `${k}.bpmn` in files);
99
+ if (named)
100
+ return named;
101
+ }
102
+ }
103
+ catch { /* a malformed descriptor is not worth failing a compile over */ }
104
+ }
105
+ // No descriptor (a project scaffolded some other way): a sibling `caseplan.json`
106
+ // still says what the project ships, and only the output name is in doubt.
107
+ if (existsSync(join(dir, 'caseplan.json')))
108
+ return 'caseplan.json';
109
+ return basename(outPath);
110
+ }
111
+ /**
112
+ * Keep the sibling `entry-points.json` in step with the caseplan's trigger nodes:
113
+ * the runtime discovers triggers there, so a trigger node with no matching
114
+ * entry-point is invisible at deploy. One entry per profile-owned trigger
115
+ * node — preserving an existing entry's `uniqueId`, minting a *deterministic*
116
+ * one (so rebuilds stay byte-stable) for new triggers, and dropping orphans.
117
+ * No-op (returns -1) when there is no `entry-points.json` beside the output (e.g.
118
+ * a bare `serialize` outside a scaffolded project).
119
+ */
120
+ function syncEntryPoints(caseplan, outPath) {
121
+ const epPath = join(dirname(outPath), 'entry-points.json');
122
+ if (!existsSync(epPath))
123
+ return -1;
124
+ const ep = JSON.parse(readFileSync(epPath, 'utf8'));
125
+ const existing = new Map((ep.entryPoints ?? []).map((e) => [String(e.filePath).split('#')[1] ?? '', e]));
126
+ const base = packagedCaseFileName(dirname(outPath), outPath);
127
+ const triggerNodes = caseplan.nodes.filter((n) => n[CASE_FORMAT_PROFILE.nodeTypeField] === CASE_FORMAT_PROFILE.triggerNodeType);
128
+ ep.entryPoints = triggerNodes.map((n) => {
129
+ const prev = existing.get(n.id);
130
+ // Project the case's In/Out args into this trigger's input/output schemas
131
+ // (In-args scoped to this trigger by elementId; Out-args to every entry).
132
+ const { input, output } = entryPointIO(caseplan.variables, n.id);
133
+ return {
134
+ filePath: `/content/${base}.bpmn#${n.id}`,
135
+ uniqueId: prev?.uniqueId ?? stableUuid(`entrypoint:${n.id}`),
136
+ type: 'CaseManagement',
137
+ input,
138
+ output,
139
+ displayName: (n.data && n.data.label) || n.id,
140
+ };
141
+ });
142
+ writeFileSync(epPath, JSON.stringify(ep, null, 2) + '\n');
143
+ return triggerNodes.length;
144
+ }
145
+ /**
146
+ * Keep a scaffolded project's solution-resource sidecar in step with the Case
147
+ * artifact. `resources refresh` reads bindings_v2.json, not caseplan.json, and
148
+ * succeeds with zero warnings when the sidecar is stale or empty.
149
+ *
150
+ * Non-connector resources come from root binding pairs and referenced tasks.
151
+ * Connector connection and folder bindings have different resource keys, so
152
+ * their relationship comes from the context[] that references both binding ids.
153
+ * No-op when compiling outside a scaffolded project.
154
+ */
155
+ function syncBindingsV2(caseplan, outPath) {
156
+ const sidecarPath = join(dirname(outPath), 'bindings_v2.json');
157
+ if (!existsSync(sidecarPath))
158
+ return -1;
159
+ const bindings = Array.isArray(caseplan.bindings)
160
+ ? caseplan.bindings.filter(isRecord)
161
+ : [];
162
+ const byId = new Map(bindings
163
+ .filter((binding) => typeof binding.id === 'string')
164
+ .map((binding) => [binding.id, binding]));
165
+ const resources = [];
166
+ const grouped = new Map();
167
+ for (const binding of bindings) {
168
+ const resource = stringValue(binding.resource);
169
+ const key = stringValue(binding.resourceKey);
170
+ if (!resource || !key || resource.toLowerCase() === 'connection')
171
+ continue;
172
+ const groupKey = `${resource}\0${key}`;
173
+ let group = grouped.get(groupKey);
174
+ if (!group) {
175
+ group = { resource, key, value: {} };
176
+ grouped.set(groupKey, group);
177
+ }
178
+ const property = stringValue(binding.propertyAttribute) ?? stringValue(binding.name);
179
+ if (property)
180
+ group.value[property] = { defaultValue: binding.default ?? key };
181
+ const subType = stringValue(binding.resourceSubType);
182
+ if (subType)
183
+ group.subType = subType;
184
+ }
185
+ const referenceTaskSubTypes = new Map([
186
+ ['process', 'ProcessOrchestration'],
187
+ ['agent', 'Agent'],
188
+ ['rpa', undefined],
189
+ ['api-workflow', 'Api'],
190
+ ['case-management', 'CaseManagement'],
191
+ ['flow-process', 'ProcessOrchestration'],
192
+ ]);
193
+ const seenConnections = new Set();
194
+ const connectionResources = [];
195
+ visitRecords(caseplan, (record) => {
196
+ const type = stringValue(record.type);
197
+ const data = isRecord(record.data) ? record.data : undefined;
198
+ if (type && data && referenceTaskSubTypes.has(type)) {
199
+ const name = referencedBindingValue(data.name, byId);
200
+ const folderPath = referencedBindingValue(data.folderPath, byId);
201
+ if (name && folderPath) {
202
+ const key = referencedBindingResourceKey(data.name, byId)
203
+ ?? referencedBindingResourceKey(data.folderPath, byId)
204
+ ?? `${folderPath}.${name}`;
205
+ const groupKey = `process\0${key}`;
206
+ if (!grouped.has(groupKey)) {
207
+ grouped.set(groupKey, {
208
+ resource: 'process',
209
+ key,
210
+ value: {
211
+ name: { defaultValue: name },
212
+ folderPath: { defaultValue: folderPath },
213
+ },
214
+ subType: referenceTaskSubTypes.get(type),
215
+ });
216
+ }
217
+ }
218
+ }
219
+ if (!Array.isArray(record.context))
220
+ return;
221
+ const context = new Map(record.context
222
+ .filter(isRecord)
223
+ .filter((row) => typeof row.name === 'string')
224
+ .map((row) => [row.name, row.value]));
225
+ const connector = stringValue(context.get('connectorKey'));
226
+ const connectionId = referencedBindingValue(context.get('connection'), byId);
227
+ const folderKey = referencedBindingValue(context.get('folderKey'), byId);
228
+ if (!connector || !connectionId || !folderKey || seenConnections.has(connectionId))
229
+ return;
230
+ seenConnections.add(connectionId);
231
+ connectionResources.push({
232
+ resource: 'Connection',
233
+ key: connectionId,
234
+ value: {
235
+ connectionId: { defaultValue: connectionId },
236
+ folderKey: { defaultValue: folderKey },
237
+ },
238
+ metadata: { connector },
239
+ });
240
+ });
241
+ for (const group of grouped.values()) {
242
+ resources.push({
243
+ resource: group.resource,
244
+ key: group.key,
245
+ value: group.value,
246
+ metadata: group.subType ? { subType: group.subType } : {},
247
+ });
248
+ }
249
+ resources.push(...connectionResources);
250
+ writeFileSync(sidecarPath, JSON.stringify({ version: '2.0', resources }, null, 2) + '\n');
251
+ return resources.length;
252
+ }
253
+ function referencedBindingValue(value, bindings) {
254
+ const ref = stringValue(value);
255
+ if (!ref)
256
+ return undefined;
257
+ if (!ref.startsWith('=bindings.'))
258
+ return ref;
259
+ const binding = bindings.get(ref.slice('=bindings.'.length));
260
+ return binding && (stringValue(binding.default) ?? stringValue(binding.resourceKey));
261
+ }
262
+ function referencedBindingResourceKey(value, bindings) {
263
+ const ref = stringValue(value);
264
+ if (!ref?.startsWith('=bindings.'))
265
+ return undefined;
266
+ return stringValue(bindings.get(ref.slice('=bindings.'.length))?.resourceKey);
267
+ }
268
+ function visitRecords(value, visit) {
269
+ if (Array.isArray(value)) {
270
+ for (const item of value)
271
+ visitRecords(item, visit);
272
+ return;
273
+ }
274
+ if (!isRecord(value))
275
+ return;
276
+ visit(value);
277
+ for (const child of Object.values(value))
278
+ visitRecords(child, visit);
279
+ }
280
+ function isRecord(value) {
281
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
282
+ }
283
+ function stringValue(value) {
284
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
285
+ }
286
+ /** A deterministic UUID-shaped id (not a real v4 — the schema only needs a stable string). */
287
+ function stableUuid(seed) {
288
+ const h = createHash('sha256').update(seed).digest('hex');
289
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
290
+ }
291
+ runWhenInvokedDirectly(import.meta.url, 'compile', run);
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { type CliExitCode } from '../cli-run.js';
3
+ /**
4
+ * `run(argv)` is the tool contract the family-first `flow-sdk` CLI loads
5
+ * (`cli/common.ts` → `invoke`). It must NOT read `process.argv` — under the
6
+ * unified CLI that still holds `case decompile …`, so the positional scan would
7
+ * pick up the family word. Errors throw; both callers report and set exit 1.
8
+ */
9
+ export declare function run(argv: string[]): CliExitCode;
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * decompile-cli — caseplan.json → <Name>.case.ts
4
+ *
5
+ * Usage:
6
+ * node --experimental-strip-types decompile-cli.js <caseplan.json> [-o Name.case.ts] [--import <specifier>] [--library <dir>] [--best-effort] [--no-pipeline]
7
+ *
8
+ * The reverse of compile-cli: reads a V20-V30 caseplan and emits builder source whose
9
+ * default export re-serializes to the same caseplan (structurally). `--import`
10
+ * sets the module specifier of the emitted `import { casePlan, rule }` line
11
+ * (default the package's `./case` subpath export) so the
12
+ * emitted file resolves for a package consumer. The library default
13
+ * (`decompile()` in decompile.js) stays repo-relative for in-tree callers —
14
+ * mirroring how the Flow arm's decompile-cli overrides it. By default the
15
+ * command also emits a `<Name>.pipeline.mjs` helper that recompiles edits
16
+ * through the public Case CLI. Pass `--no-pipeline` to skip it.
17
+ */
18
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
19
+ import { resolveLibraryDir } from '../registry/cache.js';
20
+ import { basename, resolve } from 'node:path';
21
+ import { runWhenInvokedDirectly } from '../cli-run.js';
22
+ import { Library } from '../core/library.js';
23
+ import { decompileWithDiagnostics } from './decompile.js';
24
+ import { CASE_IMPORT } from '../package-name.js';
25
+ function opt(argv, name) {
26
+ const i = argv.indexOf(name);
27
+ return i >= 0 ? argv[i + 1] : undefined;
28
+ }
29
+ /** Derive a PascalCase base name from the case name for the default output file. */
30
+ function baseName(plan) {
31
+ const src = plan.name ?? plan.id ?? 'Case';
32
+ const pascal = src
33
+ .split(/[^A-Za-z0-9]+/)
34
+ .filter(Boolean)
35
+ .map((w) => w[0].toUpperCase() + w.slice(1))
36
+ .join('');
37
+ return pascal || 'Case';
38
+ }
39
+ /**
40
+ * `run(argv)` is the tool contract the family-first `flow-sdk` CLI loads
41
+ * (`cli/common.ts` → `invoke`). It must NOT read `process.argv` — under the
42
+ * unified CLI that still holds `case decompile …`, so the positional scan would
43
+ * pick up the family word. Errors throw; both callers report and set exit 1.
44
+ */
45
+ export function run(argv) {
46
+ if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
47
+ console.error('usage: decompile <caseplan.json> [-o Name.case.ts] [--import <specifier>] [--library <dir>] [--best-effort] [--no-pipeline]');
48
+ return 2;
49
+ }
50
+ const flags = new Set(['-o', '--import', '--library']);
51
+ const pos = argv.find((a, i) => !flags.has(a) && !flags.has(argv[i - 1]) && !a.startsWith('-'));
52
+ if (!pos) {
53
+ console.error('decompile: missing <caseplan.json>');
54
+ return 2;
55
+ }
56
+ const plan = JSON.parse(readFileSync(pos, 'utf8'));
57
+ const libraryDir = resolveLibraryDir(opt(argv, '--library'));
58
+ const library = libraryDir && existsSync(`${libraryDir}/index.json`) ? new Library(libraryDir) : undefined;
59
+ const importSpecifier = opt(argv, '--import') ?? CASE_IMPORT;
60
+ const bestEffort = argv.includes('--best-effort');
61
+ const result = decompileWithDiagnostics(plan, {
62
+ importSpecifier,
63
+ library,
64
+ bestEffort,
65
+ });
66
+ const out = opt(argv, '-o') ?? `${baseName(plan)}.case.ts`;
67
+ writeFileSync(out, result.source);
68
+ console.log(`decompile: wrote ${basename(out)}`);
69
+ for (const diagnostic of result.diagnostics) {
70
+ console.error(`decompile: [${diagnostic.code}] ${diagnostic.location}: ${diagnostic.message}`);
71
+ }
72
+ if (!argv.includes('--no-pipeline')) {
73
+ const pipelinePath = out.replace(/\.case\.ts$|\.ts$/, '') + '.pipeline.mjs';
74
+ writeFileSync(pipelinePath, pipelineScript(resolve(pos), resolve(out), importSpecifier, bestEffort, libraryDir ? resolve(libraryDir) : undefined));
75
+ console.log(`decompile: wrote ${basename(pipelinePath)}`);
76
+ }
77
+ return 0;
78
+ }
79
+ /**
80
+ * Case preserves its non-authoring lanes in the generated source, so unlike
81
+ * Flow it needs no three-way merge. The wrapper recompiles that source while
82
+ * feeding the original caseplan back as the binding registry; this preserves
83
+ * the resource keys that the typed source deliberately names symbolically.
84
+ */
85
+ function pipelineScript(originalPath, tsPath, importSpecifier, bestEffort, libraryDir) {
86
+ const base = tsPath.replace(/\.case\.ts$|\.ts$/, '');
87
+ return `#!/usr/bin/env node
88
+ // Generated by case decompile — edit ${basename(tsPath)}, then run this file.
89
+ import { execFileSync, spawnSync } from 'node:child_process';
90
+ import { existsSync } from 'node:fs';
91
+
92
+ const ORIGINAL = ${JSON.stringify(originalPath)};
93
+ const TS = ${JSON.stringify(tsPath)};
94
+ const OUTPUT = ${JSON.stringify(base + '.caseplan.json')};
95
+ const IMPORT = ${JSON.stringify(importSpecifier)};
96
+ const LIBRARY = ${JSON.stringify(libraryDir)};
97
+ const BEST_EFFORT = ${JSON.stringify(bestEffort)};
98
+
99
+ const uipProbe = spawnSync('uip', ['maestro', 'case', 'compile', '--help'], { stdio: 'ignore' });
100
+ const frontDoor = !uipProbe.error && uipProbe.status === 0
101
+ ? { file: 'uip', prefix: ['maestro', 'case'] }
102
+ : { file: 'npx', prefix: ['--no-install', 'flow-sdk', 'case'] };
103
+ const run = (verb, args) =>
104
+ execFileSync(frontDoor.file, [...frontDoor.prefix, verb, ...args], { stdio: 'inherit' });
105
+ const withLibrary = (args) => LIBRARY ? [...args, '--library', LIBRARY] : args;
106
+
107
+ if (!existsSync(TS)) {
108
+ const decompileArgs = [ORIGINAL, '-o', TS, '--import', IMPORT, '--no-pipeline'];
109
+ if (BEST_EFFORT) decompileArgs.push('--best-effort');
110
+ run('decompile', withLibrary(decompileArgs));
111
+ }
112
+
113
+ run('compile', withLibrary([TS, '-o', OUTPUT, '--bindings', ORIGINAL]));
114
+ console.log('\\n>>> Wrote ' + ${JSON.stringify(base + '.caseplan.json')});
115
+ `;
116
+ }
117
+ runWhenInvokedDirectly(import.meta.url, 'case-decompile', run);
@@ -0,0 +1,187 @@
1
+ /**
2
+ * case/decompile — invert an authorable Case JSON document into fluent builder
3
+ * source. At the SDK write floor, compiling the generated source reproduces the
4
+ * input bytes; platform-owned preservation lanes are handled separately.
5
+ */
6
+ import type { Library } from '../core/library.js';
7
+ interface IoRow {
8
+ id?: string;
9
+ name?: string;
10
+ type?: string;
11
+ default?: unknown;
12
+ body?: unknown;
13
+ _jsonSchema?: unknown;
14
+ custom?: boolean;
15
+ elementId?: string;
16
+ var?: string;
17
+ source?: string;
18
+ value?: unknown;
19
+ target?: string;
20
+ subType?: string;
21
+ displayName?: string;
22
+ required?: unknown;
23
+ options?: unknown;
24
+ }
25
+ interface SubscriptionBag {
26
+ serviceType?: string;
27
+ context?: IoRow[];
28
+ inputs?: unknown[];
29
+ outputs?: IoRow[];
30
+ bindings?: unknown[];
31
+ [key: string]: unknown;
32
+ }
33
+ interface Rule {
34
+ rule: string;
35
+ id?: string;
36
+ selectedStageId?: string;
37
+ selectedStageIds?: string[];
38
+ selectedTasksIds?: string[];
39
+ conditionExpression?: string;
40
+ uipath?: SubscriptionBag;
41
+ slaId?: string;
42
+ escalationId?: string;
43
+ }
44
+ interface Condition {
45
+ id?: string;
46
+ displayName?: string;
47
+ rules?: Rule[][];
48
+ isInterrupting?: boolean;
49
+ marksStageComplete?: boolean;
50
+ type?: string;
51
+ exitToStageId?: string;
52
+ marksCaseComplete?: boolean;
53
+ }
54
+ interface EscalationWire {
55
+ id?: string;
56
+ displayName?: string;
57
+ triggerInfo?: {
58
+ type?: string;
59
+ atRiskPercentage?: number;
60
+ };
61
+ action?: {
62
+ type?: string;
63
+ recipients?: Array<{
64
+ scope?: string;
65
+ target?: string;
66
+ value?: string;
67
+ }>;
68
+ };
69
+ }
70
+ interface SlaWire {
71
+ id?: string;
72
+ displayName?: string;
73
+ expression?: string;
74
+ count?: number;
75
+ unit?: string;
76
+ escalationRule?: EscalationWire[];
77
+ }
78
+ interface TaskNode {
79
+ id?: string;
80
+ displayName?: string;
81
+ type: string;
82
+ data?: Record<string, any>;
83
+ shouldRunOnlyOnce?: boolean;
84
+ isRequired?: boolean;
85
+ skipCondition?: string;
86
+ description?: string;
87
+ entryConditions?: Condition[];
88
+ conditions?: unknown;
89
+ nonSequentialRunConditions?: unknown;
90
+ [key: string]: unknown;
91
+ }
92
+ interface StageNode {
93
+ id?: string;
94
+ type: string;
95
+ stageType?: string;
96
+ data?: {
97
+ label?: string;
98
+ description?: string;
99
+ isRequired?: boolean;
100
+ tasks?: TaskNode[][];
101
+ entryConditions?: Condition[];
102
+ exitConditions?: Condition[];
103
+ slaRules?: SlaWire[];
104
+ adhocOrchestrationData?: unknown;
105
+ [key: string]: unknown;
106
+ };
107
+ position?: unknown;
108
+ }
109
+ interface TriggerNode {
110
+ id?: string;
111
+ type: string;
112
+ data?: Record<string, any>;
113
+ }
114
+ interface VarEntry extends IoRow {
115
+ name: string;
116
+ type: string;
117
+ }
118
+ interface BindingEntry {
119
+ id?: string;
120
+ resourceKey?: string;
121
+ default?: string;
122
+ }
123
+ interface CasePlan {
124
+ id?: string;
125
+ name?: string;
126
+ description?: string;
127
+ version?: string;
128
+ bindings?: BindingEntry[];
129
+ variables?: {
130
+ inputs?: VarEntry[];
131
+ outputs?: VarEntry[];
132
+ inputOutputs?: VarEntry[];
133
+ };
134
+ metadata?: {
135
+ caseIdentifier?: string;
136
+ caseIdentifierType?: 'constant' | 'external';
137
+ caseAppEnabled?: boolean;
138
+ caseExitRules?: Condition[];
139
+ slaRules?: SlaWire[];
140
+ caseAppConfig?: {
141
+ caseSummary?: unknown;
142
+ sections?: Array<{
143
+ id?: unknown;
144
+ title?: unknown;
145
+ details?: unknown;
146
+ error?: unknown;
147
+ titleError?: unknown;
148
+ [key: string]: unknown;
149
+ }>;
150
+ stageOrder?: unknown;
151
+ hiddenStageIds?: unknown;
152
+ [key: string]: unknown;
153
+ };
154
+ adhocCaseEndData?: unknown;
155
+ allowAdhocOptionalStageTasks?: unknown;
156
+ waitForHumanSelectNextStageDFConnector?: unknown;
157
+ [key: string]: unknown;
158
+ };
159
+ nodes?: Array<StageNode | TriggerNode | Record<string, any>>;
160
+ edges?: unknown[];
161
+ layout?: unknown;
162
+ [key: string]: unknown;
163
+ }
164
+ export interface DecompileOptions {
165
+ /** Module specifier for the generated authoring import. */
166
+ importSpecifier?: string;
167
+ /** Connector library used to recover symbolic `.connector(key, action, …)`. */
168
+ library?: Library;
169
+ /**
170
+ * Emit an intentionally non-buildable repair scaffold for unsupported task
171
+ * kinds and unresolved task/stage references instead of stopping at the first
172
+ * one. Strict fidelity remains the default.
173
+ */
174
+ bestEffort?: boolean;
175
+ }
176
+ export interface CaseDecompileDiagnostic {
177
+ code: 'UNSUPPORTED_TASK_KIND' | 'UNKNOWN_STAGE_REFERENCE' | 'UNKNOWN_TASK_REFERENCE' | 'UNKNOWN_EXIT_TARGET';
178
+ message: string;
179
+ location: string;
180
+ }
181
+ export interface CaseDecompileResult {
182
+ source: string;
183
+ diagnostics: CaseDecompileDiagnostic[];
184
+ }
185
+ export declare function decompileWithDiagnostics(plan: CasePlan, options?: DecompileOptions): CaseDecompileResult;
186
+ export declare function decompile(plan: CasePlan, options?: DecompileOptions): string;
187
+ export {};