@uipath/maestro-builder-sdk 6.16.6 → 6.16.8

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.
@@ -22,7 +22,7 @@
22
22
  * Variables are SCOPED: a sub-process sees the enclosing variables plus its own.
23
23
  */
24
24
  import { type ExprDiagnostic } from '../core/expr-check.js';
25
- import { type BuiltBpmn } from './bpmn-sdk.js';
25
+ import type { BuiltBpmn } from './bpmn-sdk.js';
26
26
  /** A diagnostic plus the element it was found in. */
27
27
  export interface BpmnLocatedDiagnostic extends ExprDiagnostic {
28
28
  where: string;
@@ -22,7 +22,7 @@
22
22
  * Variables are SCOPED: a sub-process sees the enclosing variables plus its own.
23
23
  */
24
24
  import { checkExpression } from '../core/expr-check.js';
25
- import { nodeDeclaredVars } from './bpmn-sdk.js';
25
+ import { nodeDeclaredVars } from './declared-vars.js';
26
26
  const NOUN = 'variable';
27
27
  const NAMESPACE = 'vars';
28
28
  const BINDING_NOUN = 'binding';
@@ -27,6 +27,7 @@ import { type DataServiceOperation } from './data-service.js';
27
27
  export type { DataServiceOperation } from './data-service.js';
28
28
  export { BpmnBuildError } from './bpmn-expr-check.js';
29
29
  export type { BpmnLocatedDiagnostic } from './bpmn-expr-check.js';
30
+ export { connectorOutputVars, nodeDeclaredVars, typedNodeDeclaredVars } from './declared-vars.js';
30
31
  /** ISO-8601 timer specification (one of duration / date / cycle). */
31
32
  export interface TimerSpec {
32
33
  /** Fire after this ISO-8601 duration, e.g. `'PT30S'`. */
@@ -3135,58 +3136,6 @@ export type BpmnConnectorOpts = ConnectorOpts & ActivityOpts & {
3135
3136
  */
3136
3137
  outputVar?: string;
3137
3138
  };
3138
- /**
3139
- * The variables a connector task's output rows land in.
3140
- *
3141
- * Per-node by default, because a `uipath:output`'s `var` IS the variable
3142
- * declaration as far as the platform is concerned (its canvas model maps every
3143
- * node output to a variable keyed by `var`). A shared name would therefore mean
3144
- * two connectors writing one variable, with the second silently clobbering the
3145
- * first — and it is the reason both the serializer and the expression check need
3146
- * the same answer, hence one function.
3147
- *
3148
- * @param n - The connector node.
3149
- * @returns The response and error variable names.
3150
- *
3151
- * @internal
3152
- */
3153
- export declare function connectorOutputVars(n: Extract<BpmnNode, {
3154
- kind: 'connector';
3155
- }>): {
3156
- response: string;
3157
- error: string;
3158
- };
3159
- /**
3160
- * The variables a typed node writes — the ONE definition of that set.
3161
- *
3162
- * It had grown three: this one (what an expression may read), `implicitNodeVars` in
3163
- * serialize (what gets declared in `uipath:variables`), and `derivedVariableIds` in
3164
- * decompile (what a decompiled file must NOT re-declare). All three must agree, and
3165
- * adding `outputRows` proved they do not stay agreed on their own: two were updated,
3166
- * this one was missed, and a human task's mapped output stopped being visible to the
3167
- * expression checker — `vars.decision` reported undeclared for a variable the node
3168
- * plainly writes. So serialize now calls this instead of repeating it, and only
3169
- * decompile's copy is separate, which its own comment already flags as load-bearing.
3170
- *
3171
- * @param n - The typed node.
3172
- * @returns The variable ids its output rows write.
3173
- * @internal
3174
- */
3175
- export declare function typedNodeDeclaredVars(n: Extract<BpmnNode, {
3176
- kind: 'typed';
3177
- }>): string[];
3178
- /**
3179
- * Every variable name a node DECLARES by writing to it — the platform counts a
3180
- * node's output `var` as a declaration, so a downstream `=vars.<name>` resolves
3181
- * against it without any `uipath:variables` entry. The expression check mirrors
3182
- * that, or it would reject reads the platform accepts.
3183
- *
3184
- * @param n - The node to inspect.
3185
- * @returns The variable names it declares, if any.
3186
- *
3187
- * @internal
3188
- */
3189
- export declare function nodeDeclaredVars(n: BpmnNode): string[];
3190
3139
  /** A sub-process body: the same graph methods, plus an internal node builder. */
3191
3140
  export declare class SubProcessBuilder extends ScopeBuilder {
3192
3141
  /**
@@ -2,9 +2,11 @@ import { connector as makeConnector } from '../core/actions.js';
2
2
  import { checkBpmnExpressions, BpmnBuildError } from './bpmn-expr-check.js';
3
3
  import { BPMN_SCHEMA_VERSIONS } from './format-profile.js';
4
4
  import { schemaVersionRefusal } from '../schema-version.js';
5
- import { bindingRequiredFields, REGISTRY_GAPS, registryType, typedNodeOutputVar } from './typed-node.js';
5
+ import { bindingRequiredFields, REGISTRY_GAPS, registryType } from './typed-node.js';
6
6
  import { DATA_SERVICE_ACTIVITY_TYPE, DATA_SERVICE_CONNECTOR_KEY, dataServiceWire } from './data-service.js';
7
7
  export { BpmnBuildError } from './bpmn-expr-check.js';
8
+ // @internal helpers kept on the published /bpmn subpath; SDK code imports declared-vars.js.
9
+ export { connectorOutputVars, nodeDeclaredVars, typedNodeDeclaredVars } from './declared-vars.js';
8
10
  function normTimer(t) {
9
11
  return typeof t === 'string' ? { duration: t } : t;
10
12
  }
@@ -2264,47 +2266,6 @@ class ScopeBuilder {
2264
2266
  return this;
2265
2267
  }
2266
2268
  }
2267
- /**
2268
- * The variables a connector task's output rows land in.
2269
- *
2270
- * Per-node by default, because a `uipath:output`'s `var` IS the variable
2271
- * declaration as far as the platform is concerned (its canvas model maps every
2272
- * node output to a variable keyed by `var`). A shared name would therefore mean
2273
- * two connectors writing one variable, with the second silently clobbering the
2274
- * first — and it is the reason both the serializer and the expression check need
2275
- * the same answer, hence one function.
2276
- *
2277
- * @param n - The connector node.
2278
- * @returns The response and error variable names.
2279
- *
2280
- * @internal
2281
- */
2282
- export function connectorOutputVars(n) {
2283
- return { response: n.outputVar ?? `${n.id}_response`, error: `${n.id}_Error` };
2284
- }
2285
- /**
2286
- * The variables a typed node writes — the ONE definition of that set.
2287
- *
2288
- * It had grown three: this one (what an expression may read), `implicitNodeVars` in
2289
- * serialize (what gets declared in `uipath:variables`), and `derivedVariableIds` in
2290
- * decompile (what a decompiled file must NOT re-declare). All three must agree, and
2291
- * adding `outputRows` proved they do not stay agreed on their own: two were updated,
2292
- * this one was missed, and a human task's mapped output stopped being visible to the
2293
- * expression checker — `vars.decision` reported undeclared for a variable the node
2294
- * plainly writes. So serialize now calls this instead of repeating it, and only
2295
- * decompile's copy is separate, which its own comment already flags as load-bearing.
2296
- *
2297
- * @param n - The typed node.
2298
- * @returns The variable ids its output rows write.
2299
- * @internal
2300
- */
2301
- export function typedNodeDeclaredVars(n) {
2302
- // Spelled-out rows REPLACE the derived pair, so they are the whole answer.
2303
- if (n.outputRows)
2304
- return n.outputRows.map((r) => r.var).filter((v) => v !== undefined);
2305
- const v = typedNodeOutputVar(n.id, n.type, n.outputVar, n.spec);
2306
- return [...(v ? [v] : []), ...Object.keys(n.outputs ?? {})];
2307
- }
2308
2269
  /**
2309
2270
  * Fill in `activity` on a connector task from the `operation` beside it.
2310
2271
  *
@@ -2348,30 +2309,6 @@ function defaultActivityIdentityRows(type, context, rows) {
2348
2309
  return rows;
2349
2310
  return [...rows, { name: 'activity', type: 'string', value: operation }];
2350
2311
  }
2351
- /**
2352
- * Every variable name a node DECLARES by writing to it — the platform counts a
2353
- * node's output `var` as a declaration, so a downstream `=vars.<name>` resolves
2354
- * against it without any `uipath:variables` entry. The expression check mirrors
2355
- * that, or it would reject reads the platform accepts.
2356
- *
2357
- * @param n - The node to inspect.
2358
- * @returns The variable names it declares, if any.
2359
- *
2360
- * @internal
2361
- */
2362
- export function nodeDeclaredVars(n) {
2363
- if (n.kind === 'connector') {
2364
- const { response, error } = connectorOutputVars(n);
2365
- return [response, error];
2366
- }
2367
- if (n.kind === 'typed')
2368
- return typedNodeDeclaredVars(n);
2369
- if (n.kind === 'scriptTask')
2370
- return Object.keys(n.outputs);
2371
- if (n.kind === 'task')
2372
- return Object.keys(n.set);
2373
- return [];
2374
- }
2375
2312
  /** A sub-process body: the same graph methods, plus an internal node builder. */
2376
2313
  export class SubProcessBuilder extends ScopeBuilder {
2377
2314
  /**
@@ -15,7 +15,7 @@
15
15
  * implicit join — the diagnostic is a `warning`, and its comment says which
16
16
  * platform rule it corresponds to and how the two differ.
17
17
  */
18
- import { type BuiltBpmn } from './bpmn-sdk.js';
18
+ import type { BuiltBpmn } from './bpmn-sdk.js';
19
19
  import { type ConnectorCheckOpts } from '../core/connector-checks.js';
20
20
  import { type EventCheckOpts } from '../core/event-checks.js';
21
21
  export interface Diagnostic {
@@ -1,21 +1,4 @@
1
- /**
2
- * bpmn/check — fast static validation of a BuiltBpmn before serialization.
3
- *
4
- * Surfaces the common Maestro canvas-rule failures early (dangling flow refs,
5
- * duplicate ids, a gateway branch with no condition, a superfluous gateway, an
6
- * implicit join, a missing start event, a boundary event attached to nothing, an
7
- * empty timer) so authoring gets instant feedback. The authoritative gate is
8
- * still `uip maestro bpmn validate` (`validateBpmnCanvas`) on the emitted
9
- * `.bpmn`.
10
- *
11
- * **An `error` here must mirror a real platform rule.** Being stricter than
12
- * `validate` is worse than being looser: it refuses processes that deploy and run
13
- * correctly, and the author has no way to appeal. Where this file is deliberately
14
- * stricter than the platform — an unconditioned inclusive-gateway branch, an
15
- * implicit join — the diagnostic is a `warning`, and its comment says which
16
- * platform rule it corresponds to and how the two differ.
17
- */
18
- import { nodeDeclaredVars } from './bpmn-sdk.js';
1
+ import { nodeDeclaredVars } from './declared-vars.js';
19
2
  import { allNodes, folderCompanionKeys, implicitNodeVars, processId } from './serialize.js';
20
3
  import { KNOWN_METHOD_SET } from './known-methods.js';
21
4
  import { EQUALS_EXPR_DIALECT, checkConnectorContract, checkConnectorLookups, checkConnectorSchema, checkBindingLabels, } from '../core/connector-checks.js';
@@ -20,7 +20,7 @@
20
20
  */
21
21
  import type BpmnModdle from 'bpmn-moddle';
22
22
  import type { ModdleElement } from 'bpmn-moddle';
23
- import { type BpmnNode } from './bpmn-sdk.js';
23
+ import type { BpmnNode } from './bpmn-sdk.js';
24
24
  import type { Library } from '../core/library.js';
25
25
  import type { Bindings } from '../core/bindings.js';
26
26
  type El = ModdleElement;
@@ -1,4 +1,4 @@
1
- import { connectorOutputVars } from './bpmn-sdk.js';
1
+ import { connectorOutputVars } from './declared-vars.js';
2
2
  import { EQUALS_EXPR_DIALECT } from '../core/connector-checks.js';
3
3
  import { buildConnectorInputs, nestConnectorBody, transportHttpMethod } from '../core/connector-inputs.js';
4
4
  export function createConnectorTask(ctx, n) {
@@ -0,0 +1,60 @@
1
+ /**
2
+ * bpmn/declared-vars — which variables a BPMN node declares by writing to them.
3
+ *
4
+ * The builder, the expression check and the serializer all need the one answer.
5
+ * It lives outside `bpmn-sdk.ts` so the checker does not import the builder back
6
+ * (the runtime import cycle FB003 reported).
7
+ */
8
+ import type { BpmnNode } from './bpmn-sdk.js';
9
+ /**
10
+ * The variables a connector task's output rows land in.
11
+ *
12
+ * Per-node by default, because a `uipath:output`'s `var` IS the variable
13
+ * declaration as far as the platform is concerned (its canvas model maps every
14
+ * node output to a variable keyed by `var`). A shared name would therefore mean
15
+ * two connectors writing one variable, with the second silently clobbering the
16
+ * first — and it is the reason both the serializer and the expression check need
17
+ * the same answer, hence one function.
18
+ *
19
+ * @param n - The connector node.
20
+ * @returns The response and error variable names.
21
+ *
22
+ * @internal
23
+ */
24
+ export declare function connectorOutputVars(n: Extract<BpmnNode, {
25
+ kind: 'connector';
26
+ }>): {
27
+ response: string;
28
+ error: string;
29
+ };
30
+ /**
31
+ * The variables a typed node writes — the ONE definition of that set.
32
+ *
33
+ * It had grown three: this one (what an expression may read), `implicitNodeVars` in
34
+ * serialize (what gets declared in `uipath:variables`), and `derivedVariableIds` in
35
+ * decompile (what a decompiled file must NOT re-declare). All three must agree, and
36
+ * adding `outputRows` proved they do not stay agreed on their own: two were updated,
37
+ * this one was missed, and a human task's mapped output stopped being visible to the
38
+ * expression checker — `vars.decision` reported undeclared for a variable the node
39
+ * plainly writes. So serialize now calls this instead of repeating it, and only
40
+ * decompile's copy is separate, which its own comment already flags as load-bearing.
41
+ *
42
+ * @param n - The typed node.
43
+ * @returns The variable ids its output rows write.
44
+ * @internal
45
+ */
46
+ export declare function typedNodeDeclaredVars(n: Extract<BpmnNode, {
47
+ kind: 'typed';
48
+ }>): string[];
49
+ /**
50
+ * Every variable name a node DECLARES by writing to it — the platform counts a
51
+ * node's output `var` as a declaration, so a downstream `=vars.<name>` resolves
52
+ * against it without any `uipath:variables` entry. The expression check mirrors
53
+ * that, or it would reject reads the platform accepts.
54
+ *
55
+ * @param n - The node to inspect.
56
+ * @returns The variable names it declares, if any.
57
+ *
58
+ * @internal
59
+ */
60
+ export declare function nodeDeclaredVars(n: BpmnNode): string[];
@@ -0,0 +1,66 @@
1
+ import { typedNodeOutputVar } from './typed-node.js';
2
+ /**
3
+ * The variables a connector task's output rows land in.
4
+ *
5
+ * Per-node by default, because a `uipath:output`'s `var` IS the variable
6
+ * declaration as far as the platform is concerned (its canvas model maps every
7
+ * node output to a variable keyed by `var`). A shared name would therefore mean
8
+ * two connectors writing one variable, with the second silently clobbering the
9
+ * first — and it is the reason both the serializer and the expression check need
10
+ * the same answer, hence one function.
11
+ *
12
+ * @param n - The connector node.
13
+ * @returns The response and error variable names.
14
+ *
15
+ * @internal
16
+ */
17
+ export function connectorOutputVars(n) {
18
+ return { response: n.outputVar ?? `${n.id}_response`, error: `${n.id}_Error` };
19
+ }
20
+ /**
21
+ * The variables a typed node writes — the ONE definition of that set.
22
+ *
23
+ * It had grown three: this one (what an expression may read), `implicitNodeVars` in
24
+ * serialize (what gets declared in `uipath:variables`), and `derivedVariableIds` in
25
+ * decompile (what a decompiled file must NOT re-declare). All three must agree, and
26
+ * adding `outputRows` proved they do not stay agreed on their own: two were updated,
27
+ * this one was missed, and a human task's mapped output stopped being visible to the
28
+ * expression checker — `vars.decision` reported undeclared for a variable the node
29
+ * plainly writes. So serialize now calls this instead of repeating it, and only
30
+ * decompile's copy is separate, which its own comment already flags as load-bearing.
31
+ *
32
+ * @param n - The typed node.
33
+ * @returns The variable ids its output rows write.
34
+ * @internal
35
+ */
36
+ export function typedNodeDeclaredVars(n) {
37
+ // Spelled-out rows REPLACE the derived pair, so they are the whole answer.
38
+ if (n.outputRows)
39
+ return n.outputRows.map((r) => r.var).filter((v) => v !== undefined);
40
+ const v = typedNodeOutputVar(n.id, n.type, n.outputVar, n.spec);
41
+ return [...(v ? [v] : []), ...Object.keys(n.outputs ?? {})];
42
+ }
43
+ /**
44
+ * Every variable name a node DECLARES by writing to it — the platform counts a
45
+ * node's output `var` as a declaration, so a downstream `=vars.<name>` resolves
46
+ * against it without any `uipath:variables` entry. The expression check mirrors
47
+ * that, or it would reject reads the platform accepts.
48
+ *
49
+ * @param n - The node to inspect.
50
+ * @returns The variable names it declares, if any.
51
+ *
52
+ * @internal
53
+ */
54
+ export function nodeDeclaredVars(n) {
55
+ if (n.kind === 'connector') {
56
+ const { response, error } = connectorOutputVars(n);
57
+ return [response, error];
58
+ }
59
+ if (n.kind === 'typed')
60
+ return typedNodeDeclaredVars(n);
61
+ if (n.kind === 'scriptTask')
62
+ return Object.keys(n.outputs);
63
+ if (n.kind === 'task')
64
+ return Object.keys(n.set);
65
+ return [];
66
+ }
@@ -15,11 +15,10 @@
15
15
  */
16
16
  import BpmnModdle from 'bpmn-moddle';
17
17
  import { createRequire } from 'node:module';
18
- import { connectorOutputVars, } from './bpmn-sdk.js';
19
18
  import { createConnectorTask } from './connector.js';
20
19
  import { createConnectorEvent, createExternalTask, intsvcOutputVar } from './intsvc.js';
21
20
  import { createExtensionPayload, createTypedNode, rowDeclaration, typedNodeOutputVar, verbatimOutputRows } from './typed-node.js';
22
- import { typedNodeDeclaredVars } from './bpmn-sdk.js';
21
+ import { connectorOutputVars, typedNodeDeclaredVars } from './declared-vars.js';
23
22
  const require = createRequire(import.meta.url);
24
23
  const uipathDescriptor = require('./uipath-moddle.v1.json');
25
24
  const NS = {
@@ -12,7 +12,6 @@
12
12
  import { reportResult } from '../cli-result.js';
13
13
  import { writeFileSync, readFileSync, existsSync } from 'node:fs';
14
14
  import { join, dirname, basename, resolve } from 'node:path';
15
- import { createHash } from 'node:crypto';
16
15
  import { resolveCaseFile, loadBuiltCase } from './load.js';
17
16
  import { serialize } from './serialize.js';
18
17
  import { check } from './check.js';
@@ -23,6 +22,7 @@ import { defaultBindingsFile } from '../workdir.js';
23
22
  import { flagValue, runWhenInvokedDirectly } from '../cli-run.js';
24
23
  import { ensureTypeScriptRuntime } from '../node-runtime.js';
25
24
  import { CASE_FORMAT_PROFILE } from './format-profile.js';
25
+ import { sha256Uuid } from '../core/stable-id.js';
26
26
  export async function run(argv) {
27
27
  if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
28
28
  console.error('usage: compile <case.ts | BaseName> [-o caseplan.json]');
@@ -128,7 +128,7 @@ function syncEntryPoints(caseplan, outPath) {
128
128
  const { input, output } = entryPointIO(caseplan.variables, n.id);
129
129
  return {
130
130
  filePath: `/content/${base}.bpmn#${n.id}`,
131
- uniqueId: prev?.uniqueId ?? stableUuid(`entrypoint:${n.id}`),
131
+ uniqueId: prev?.uniqueId ?? sha256Uuid(`entrypoint:${n.id}`),
132
132
  type: 'CaseManagement',
133
133
  input,
134
134
  output,
@@ -279,9 +279,4 @@ function isRecord(value) {
279
279
  function stringValue(value) {
280
280
  return typeof value === 'string' && value.length > 0 ? value : undefined;
281
281
  }
282
- /** A deterministic UUID-shaped id (not a real v4 — the schema only needs a stable string). */
283
- function stableUuid(seed) {
284
- const h = createHash('sha256').update(seed).digest('hex');
285
- return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
286
- }
287
282
  runWhenInvokedDirectly(import.meta.url, 'compile', run);
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import { reportResult } from '../cli-result.js';
19
19
  import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
20
- import { resolveLibraryDir } from '../registry/cache.js';
20
+ import { resolveLibraryDir } from '../core/library-cache.js';
21
21
  import { basename, join, resolve } from 'node:path';
22
22
  import { defaultSourceOut, workDirBeside, writeSource } from '../workdir.js';
23
23
  import { flagValue, runWhenInvokedDirectly } from '../cli-run.js';
package/dist/check.js CHANGED
@@ -14,7 +14,8 @@ import { prepareCommand } from './core/cli-spelling.js';
14
14
  import { editDistance } from './core/edit-distance.js';
15
15
  import { isAnswerField } from './core/hitl-answers.js';
16
16
  import { hitlDerivesOutcomeHandles, hitlExitModel, hitlRoutesPerOutcome } from './core/hitl-routing.js';
17
- import { childStepLists, declaredExits, hasExits, stopsAtEnd } from './core/step-ports.js';
17
+ import { declaredExits, hasExits } from './core/step-ports.js';
18
+ import { childStepLists, stopsAtEnd } from './flow-step-tree.js';
18
19
  import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
19
20
  import { compareSchemaVersions, schemaVersionRefusal } from './schema-version.js';
20
21
  import { planFlowGlobals, planSharedInputs, sharedInputRoots } from './flow-variables.js';
@@ -17,7 +17,7 @@
17
17
  import { existsSync } from 'node:fs';
18
18
  import { join } from 'node:path';
19
19
  import { Library } from './library.js';
20
- import { resolveLibraryDir } from '../registry/cache.js';
20
+ import { resolveLibraryDir } from './library-cache.js';
21
21
  import { flagValue } from '../cli-run.js';
22
22
  import { defaultOverlayDir } from '../workdir.js';
23
23
  import { EQUALS_EXPR_DIALECT } from './connector-checks.js';
@@ -24,5 +24,38 @@
24
24
  * cannot read as a uuid. Coercing to unsigned first is the whole repair; the
25
25
  * hash itself is unchanged, so a seed that produced a WELL-FORMED id still
26
26
  * produces exactly that id.
27
+ *
28
+ * ## Three seed → uuid algorithms live here, and they are NOT interchangeable
29
+ *
30
+ * `stableId` (connector filter trees, event subscriptions), `fnv1aX4Uuid` (Flow
31
+ * inline-agent resource ids) and `sha256Uuid` (Case entry-point `uniqueId`) each
32
+ * produce ids that are already in shipped artifacts. Replacing one with another
33
+ * renames those resources on the next compile of every existing project. They are
34
+ * owned here so there is one place to look. The golden table in
35
+ * `tests/stable-id.test.ts` pins what each function returns, not which one a call
36
+ * site uses; `tests/cli.test.ts` pins the Case entry point's `uniqueId`. Change one
37
+ * only deliberately, updating that table and any byte-lock fixture it moves.
27
38
  */
39
+ /** A uuid-shaped id derived from `seed`. Every segment is unsigned, including the `>>> 0` fix explained above. */
28
40
  export declare function stableId(seed: string): string;
41
+ /**
42
+ * A deterministic v4-shaped uuid from a string.
43
+ *
44
+ * Used for an inline agent's `source` when the author does not pass one. It has to
45
+ * LOOK like a uuid (the platform treats it as an opaque directory name and the
46
+ * designer shows it as a folder) and it has to be STABLE, because a random one would
47
+ * make every recompile a diff of the `.flow` and a rename of a directory. FNV-1a
48
+ * ×4 with the version/variant nibbles pinned — not a cryptographic hash, and it does
49
+ * not need to be: the only requirement is that two different (flow, step) pairs do
50
+ * not collide within one project.
51
+ *
52
+ * Consumer: Flow inline-agent resource ids in `serialize.ts`.
53
+ */
54
+ export declare function fnv1aX4Uuid(seed: string): string;
55
+ /**
56
+ * A deterministic UUID-shaped id (not a real v4 — the schema only needs a stable string):
57
+ * the first 128 bits of SHA-256(`seed`), no version or variant bits set.
58
+ *
59
+ * Consumer: a Case entry point's `uniqueId` in `entry-points.json` (`case/compile-cli.ts`).
60
+ */
61
+ export declare function sha256Uuid(seed: string): string;
@@ -24,7 +24,20 @@
24
24
  * cannot read as a uuid. Coercing to unsigned first is the whole repair; the
25
25
  * hash itself is unchanged, so a seed that produced a WELL-FORMED id still
26
26
  * produces exactly that id.
27
+ *
28
+ * ## Three seed → uuid algorithms live here, and they are NOT interchangeable
29
+ *
30
+ * `stableId` (connector filter trees, event subscriptions), `fnv1aX4Uuid` (Flow
31
+ * inline-agent resource ids) and `sha256Uuid` (Case entry-point `uniqueId`) each
32
+ * produce ids that are already in shipped artifacts. Replacing one with another
33
+ * renames those resources on the next compile of every existing project. They are
34
+ * owned here so there is one place to look. The golden table in
35
+ * `tests/stable-id.test.ts` pins what each function returns, not which one a call
36
+ * site uses; `tests/cli.test.ts` pins the Case entry point's `uniqueId`. Change one
37
+ * only deliberately, updating that table and any byte-lock fixture it moves.
27
38
  */
39
+ import { createHash } from 'node:crypto';
40
+ /** A uuid-shaped id derived from `seed`. Every segment is unsigned, including the `>>> 0` fix explained above. */
28
41
  export function stableId(seed) {
29
42
  let h1 = 0x811c9dc5;
30
43
  let h2 = 0x01000193;
@@ -35,3 +48,46 @@ export function stableId(seed) {
35
48
  const hex = (n, len) => (n >>> 0).toString(16).padStart(8, '0').slice(0, len);
36
49
  return `${hex(h1, 8)}-${hex(h2, 4)}-4${hex(h1 >>> 8, 3)}-8${hex(h2 >>> 8, 3)}-${hex(h1 ^ h2, 8)}${hex(h2, 4)}`;
37
50
  }
51
+ /**
52
+ * A deterministic v4-shaped uuid from a string.
53
+ *
54
+ * Used for an inline agent's `source` when the author does not pass one. It has to
55
+ * LOOK like a uuid (the platform treats it as an opaque directory name and the
56
+ * designer shows it as a folder) and it has to be STABLE, because a random one would
57
+ * make every recompile a diff of the `.flow` and a rename of a directory. FNV-1a
58
+ * ×4 with the version/variant nibbles pinned — not a cryptographic hash, and it does
59
+ * not need to be: the only requirement is that two different (flow, step) pairs do
60
+ * not collide within one project.
61
+ *
62
+ * Consumer: Flow inline-agent resource ids in `serialize.ts`.
63
+ */
64
+ export function fnv1aX4Uuid(seed) {
65
+ const words = [];
66
+ for (let i = 0; i < 4; i++) {
67
+ let h = 0x811c9dc5 ^ (i * 0x9e3779b9);
68
+ const s = `${seed}#${i}`;
69
+ for (let j = 0; j < s.length; j++) {
70
+ h ^= s.charCodeAt(j);
71
+ h = Math.imul(h, 0x01000193) >>> 0;
72
+ }
73
+ words.push(h >>> 0);
74
+ }
75
+ const hex = words.map((w) => w.toString(16).padStart(8, '0')).join('');
76
+ return [
77
+ hex.slice(0, 8),
78
+ hex.slice(8, 12),
79
+ `4${hex.slice(13, 16)}`,
80
+ `${((parseInt(hex.slice(16, 17), 16) & 0x3) | 0x8).toString(16)}${hex.slice(17, 20)}`,
81
+ hex.slice(20, 32),
82
+ ].join('-');
83
+ }
84
+ /**
85
+ * A deterministic UUID-shaped id (not a real v4 — the schema only needs a stable string):
86
+ * the first 128 bits of SHA-256(`seed`), no version or variant bits set.
87
+ *
88
+ * Consumer: a Case entry point's `uniqueId` in `entry-points.json` (`case/compile-cli.ts`).
89
+ */
90
+ export function sha256Uuid(seed) {
91
+ const h = createHash('sha256').update(seed).digest('hex');
92
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
93
+ }
@@ -1,4 +1,3 @@
1
- import type { Step } from '../flow-sdk.js';
2
1
  /** One author-named exit: the value an arm matches on, and the port it wires. */
3
2
  export interface DeclaredExit {
4
3
  /** What `.stepSwitch()`'s arm `value` matches — the outcome or branch NAME. */
@@ -35,23 +34,4 @@ type SpecLike = {
35
34
  export declare function declaredExits(spec: SpecLike | undefined, pinnedVersion?: string): DeclaredExit[] | NoExits;
36
35
  /** Narrowing helper — `declaredExits` returns one or the other. */
37
36
  export declare function hasExits(r: DeclaredExit[] | NoExits): r is DeclaredExit[];
38
- /**
39
- * Whether a step list that hands on no tail got there by reaching an End — a
40
- * `.return()`, on some path — rather than by stopping the whole run
41
- * (`.terminate`) or leaving a loop (`.break`). Only the first leaves a sibling
42
- * `.parallel` join waiting: a terminate ends the run, join included.
43
- */
44
- export declare function stopsAtEnd(steps: readonly Step[]): boolean;
45
- /**
46
- * The step lists nested DIRECTLY inside `step` — the bodies a walk over this
47
- * flow's own tree must descend into. Exhaustive over `Step['kind']`, so a new
48
- * container kind fails to compile here instead of being silently skipped by
49
- * every walker. That is how `check`'s return scan came to miss `.stepSwitch`
50
- * arms and `.stepToList` / `.onError` bodies, and warned NO_RETURN on flows
51
- * whose every path ends in `.return()` (UV-16855).
52
- *
53
- * A subflow's child flow is deliberately NOT a child here: it is another
54
- * flow's tree, and its returns say nothing about whether THIS flow ends.
55
- */
56
- export declare function childStepLists(step: Step): readonly Step[][];
57
37
  export {};
@@ -94,53 +94,3 @@ export function declaredExits(spec, pinnedVersion) {
94
94
  export function hasExits(r) {
95
95
  return Array.isArray(r);
96
96
  }
97
- /**
98
- * Whether a step list that hands on no tail got there by reaching an End — a
99
- * `.return()`, on some path — rather than by stopping the whole run
100
- * (`.terminate`) or leaving a loop (`.break`). Only the first leaves a sibling
101
- * `.parallel` join waiting: a terminate ends the run, join included.
102
- */
103
- export function stopsAtEnd(steps) {
104
- const has = (list, kinds) => list.some((st) => kinds.has(st.kind)
105
- || (st.kind === 'branch' && (has(st.then, kinds) || has(st.otherwise, kinds)))
106
- || ((st.kind === 'switch' || st.kind === 'stepSwitch') && st.cases.some((c) => has(c.body, kinds)))
107
- || (st.kind === 'switch' && st.default !== undefined && has(st.default, kinds)));
108
- return has(steps, new Set(['return'])) && !has(steps, new Set(['terminate', 'break']));
109
- }
110
- /**
111
- * The step lists nested DIRECTLY inside `step` — the bodies a walk over this
112
- * flow's own tree must descend into. Exhaustive over `Step['kind']`, so a new
113
- * container kind fails to compile here instead of being silently skipped by
114
- * every walker. That is how `check`'s return scan came to miss `.stepSwitch`
115
- * arms and `.stepToList` / `.onError` bodies, and warned NO_RETURN on flows
116
- * whose every path ends in `.return()` (UV-16855).
117
- *
118
- * A subflow's child flow is deliberately NOT a child here: it is another
119
- * flow's tree, and its returns say nothing about whether THIS flow ends.
120
- */
121
- export function childStepLists(step) {
122
- switch (step.kind) {
123
- case 'branch':
124
- return [step.then, step.otherwise];
125
- case 'switch':
126
- return [...step.cases.map((c) => c.body), ...(step.default ? [step.default] : [])];
127
- case 'stepSwitch':
128
- return step.cases.map((c) => c.body);
129
- case 'loop':
130
- case 'doWhile':
131
- case 'stepToList':
132
- return [step.body];
133
- case 'parallel':
134
- return step.arms;
135
- case 'action':
136
- case 'break':
137
- case 'terminate':
138
- case 'stepToRef':
139
- case 'return':
140
- return [];
141
- default: {
142
- const unhandled = step;
143
- throw new Error(`childStepLists: unhandled step kind ${JSON.stringify(unhandled.kind)}`);
144
- }
145
- }
146
- }
package/dist/emit.js CHANGED
@@ -30,7 +30,7 @@ import { dirname, join } from 'node:path';
30
30
  import { serialize } from './serialize.js';
31
31
  import { Library } from './library.js';
32
32
  import { Bindings } from './bindings.js';
33
- import { resolveLibraryDir } from './registry/cache.js';
33
+ import { resolveLibraryDir } from './core/library-cache.js';
34
34
  import { defaultBindingsFile } from './workdir.js';
35
35
  /**
36
36
  * Resolve the connector library the same way `compile-cli` does: only load it