@prismatic-io/spectral 10.18.7 → 10.18.9-preview.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.
@@ -8,7 +8,7 @@ export declare const convertConfigPages: (pages: ConfigPages | undefined, userLe
8
8
  /** Converts typed QueueConfig to legacy format with usesFifoQueue and concurrencyLimit. */
9
9
  export declare const convertQueueConfig: (queueConfig: QueueConfig) => StandardQueueConfig;
10
10
  /** Converts a Flow into the structure necessary for YAML generation. */
11
- export declare const convertFlow: <TInputs extends Inputs, TActionInputs extends Inputs, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerPerformResult<TAllowsBranching, TPayload> = TriggerPerformResult<TAllowsBranching, TPayload>>(flow: Flow<TInputs, TActionInputs, TPayload, TAllowsBranching, TResult>, componentRegistry: ComponentRegistry, referenceKey: string) => Record<string, unknown>;
11
+ export declare const convertFlow: <TInputs extends Inputs, TActionInputs extends Inputs, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerPerformResult<TAllowsBranching, TPayload> = TriggerPerformResult<TAllowsBranching, TPayload>>(rawFlow: Flow<TInputs, TActionInputs, TPayload, TAllowsBranching, TResult>, componentRegistry: ComponentRegistry, referenceKey: string) => Record<string, unknown>;
12
12
  /** Converts an input value to the expected server type by its collection type. */
13
13
  export declare const convertInputValue: (value: unknown, collectionType: CollectionType | undefined) => unknown;
14
14
  /** Converts a Config Var into the structure necessary for YAML generation. */
@@ -8,6 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
11
22
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
23
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
24
  };
@@ -29,6 +40,46 @@ const integration_1 = require("./integration");
29
40
  const perform_1 = require("./perform");
30
41
  exports.CONCURRENCY_LIMIT_MAX = 15;
31
42
  exports.CONCURRENCY_LIMIT_MIN = 2;
43
+ /**
44
+ * Default `resolveItems`: a batched `trigger`'s fires return their records under
45
+ * `payload.body.data` (the wrapper {@link normalizeBatchedFlow} builds writes them there),
46
+ * so extraction is just reading that array back. Authors never write this themselves.
47
+ */
48
+ const defaultResolveItems = (_context, result) => result.payload.body.data;
49
+ /**
50
+ * Expands a flow's batched `trigger` (built with `batchFlowTrigger`) into the flat
51
+ * `onTrigger`/`onDeployTrigger`/`triggerResolver`/`onDeployResolver` shape the rest of the
52
+ * conversion pipeline already understands. The trigger fires return just `{ items }`; here we
53
+ * wrap each into a `TriggerPerformFunction` that emits `{ payload: { …payload, body: { data:
54
+ * items } } }`, synthesize the default `resolveItems`, and map the pagination callbacks onto
55
+ * the resolver `getNextDiscoveryState`. Flows without a `trigger` pass through unchanged.
56
+ *
57
+ * Returns the same `Flow` type it received; the synthesized `triggerResolver`/`onDeployResolver`
58
+ * are wire-only fields (not on the author-facing `Flow`), read downstream via `"x" in flow` checks.
59
+ */
60
+ const normalizeBatchedFlow = (flow) => {
61
+ const trigger = "trigger" in flow ? flow.trigger : undefined;
62
+ if (!trigger) {
63
+ return flow;
64
+ }
65
+ const { onTrigger, onDeploy, getNextOnTriggerPaginationState, getNextOnDeployPaginationState } = trigger;
66
+ // Wrap a batched fire (returns `{ items, response? }`) into a TriggerPerformFunction that
67
+ // emits the wire payload shape (`body.data = items`), preserving the incoming payload fields.
68
+ const wrapFire = (fire) => (context, payload) => __awaiter(void 0, void 0, void 0, function* () {
69
+ const { items, response } = yield fire(context, payload);
70
+ return Object.assign({ payload: Object.assign(Object.assign({}, payload), { body: { data: items, contentType: "application/json" } }) }, (response ? { response } : {}));
71
+ });
72
+ const _a = flow, { trigger: _omitTrigger } = _a, rest = __rest(_a, ["trigger"]);
73
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, rest), { onTrigger: wrapFire(onTrigger) }), (onDeploy ? { onDeployTrigger: wrapFire(onDeploy) } : {})), { triggerResolver: Object.assign({ resolveItems: defaultResolveItems }, (getNextOnTriggerPaginationState
74
+ ? { getNextDiscoveryState: getNextOnTriggerPaginationState }
75
+ : {})) }), (onDeploy
76
+ ? {
77
+ onDeployResolver: Object.assign({ resolveItems: defaultResolveItems }, (getNextOnDeployPaginationState
78
+ ? { getNextDiscoveryState: getNextOnDeployPaginationState }
79
+ : {})),
80
+ }
81
+ : {}));
82
+ };
32
83
  const convertIntegration = (definition) => {
33
84
  var _a, _b, _c;
34
85
  // Generate a unique reference key that will be used to reference the
@@ -94,7 +145,11 @@ const convertConfigPages = (pages, userLevelConfigured) => {
94
145
  }) })));
95
146
  };
96
147
  exports.convertConfigPages = convertConfigPages;
97
- const codeNativeIntegrationYaml = ({ name, description, category, documentation, version, labels, endpointType, triggerPreprocessFlowConfig, flows, configPages, userLevelConfigPages, scopedConfigVars, instanceProfile, componentRegistry = {}, }, referenceKey, configVars, metadata) => {
148
+ const codeNativeIntegrationYaml = ({ name, description, category, documentation, version, labels, endpointType, triggerPreprocessFlowConfig, flows: rawFlows, configPages, userLevelConfigPages, scopedConfigVars, instanceProfile, componentRegistry = {}, }, referenceKey, configVars, metadata) => {
149
+ // Expand any batched `trigger` (built with `batchFlowTrigger`) into the flat
150
+ // onTrigger/onDeployTrigger/triggerResolver/onDeployResolver shape the rest of this
151
+ // pipeline (convertFlow + the trigger reducer) already handles.
152
+ const flows = rawFlows.map((flow) => normalizeBatchedFlow(flow));
98
153
  // Find the preprocess flow config on the flow, if one exists.
99
154
  const preprocessFlows = flows.filter((flow) => flow.preprocessFlowConfig);
100
155
  // Do some validation of preprocess flow configs.
@@ -310,8 +365,11 @@ const convertFlowSchemas = (flowKey, schemas) => {
310
365
  }, {});
311
366
  };
312
367
  /** Converts a Flow into the structure necessary for YAML generation. */
313
- const convertFlow = (flow, componentRegistry, referenceKey) => {
368
+ const convertFlow = (rawFlow, componentRegistry, referenceKey) => {
314
369
  var _a;
370
+ // Expand a batched `trigger` into the flat shape this function serializes. Idempotent: a flow
371
+ // that already lacks `trigger` (including one pre-normalized by `convertIntegration`) is returned as-is.
372
+ const flow = normalizeBatchedFlow(rawFlow);
315
373
  const result = Object.assign({}, flow);
316
374
  result.onTrigger = undefined;
317
375
  result.trigger = undefined;
@@ -319,6 +377,7 @@ const convertFlow = (flow, componentRegistry, referenceKey) => {
319
377
  result.onInstanceDelete = undefined;
320
378
  result.webhookLifecycleHandlers = undefined;
321
379
  result.onExecution = undefined;
380
+ result.onDeployTrigger = undefined;
322
381
  result.preprocessFlowConfig = undefined;
323
382
  result.errorConfig = undefined;
324
383
  result.testApiKeys = undefined;
@@ -412,6 +471,30 @@ const convertFlow = (flow, componentRegistry, referenceKey) => {
412
471
  }
413
472
  : {}));
414
473
  }
474
+ const triggerResolver = "triggerResolver" in flow ? flow.triggerResolver : undefined;
475
+ const onDeployResolver = "onDeployResolver" in flow ? flow.onDeployResolver : undefined;
476
+ const batchConfig = "batchConfig" in flow ? flow.batchConfig : undefined;
477
+ // Resolver behaviors (resolveItems/getNextDiscoveryState) are serialized onto the
478
+ // synthesized trigger below. On the flow wire we emit only `triggerResolver`, the single
479
+ // config the platform reads (`trigger_resolver_batch_size` / `trigger_resolver_enabled`)
480
+ // and shares between the normal and on-deploy fires. `batchConfig`/`onDeployResolver` are
481
+ // author-side only — clear them out of the `{ ...flow }` spread.
482
+ result.triggerResolver = undefined;
483
+ result.onDeployResolver = undefined;
484
+ result.batchConfig = undefined;
485
+ if (triggerResolver || onDeployResolver) {
486
+ if (!batchConfig) {
487
+ throw new Error(`${flow.name} defines a triggerResolver/onDeployResolver but no batchConfig. Add \`batchConfig: { batchSize }\` to the flow.`);
488
+ }
489
+ if (onDeployResolver &&
490
+ (!("onDeployTrigger" in flow) || typeof flow.onDeployTrigger !== "function")) {
491
+ throw new Error(`${flow.name} declares onDeployResolver without onDeployTrigger. Set onDeployTrigger to handle the initial-deploy fire that the resolver fans out.`);
492
+ }
493
+ // `enabled: true` is required: for a "valid"-support trigger (which CNI synthesized
494
+ // triggers are) the platform only batches when the flow's resolver is enabled.
495
+ const concurrentBatchLimit = (0, convertComponent_1.validateConcurrentBatchLimit)(flow.name, "batchConfig", batchConfig.concurrentBatchLimit);
496
+ result.triggerResolver = Object.assign({ batchSize: (0, convertComponent_1.validateBatchSize)(flow.name, "batchConfig", batchConfig.batchSize), enabled: true }, (concurrentBatchLimit !== undefined ? { concurrentBatchLimit } : {}));
497
+ }
415
498
  const actionStep = {
416
499
  action: {
417
500
  key: flowFunctionKey(flow.name, "onExecution"),
@@ -695,7 +778,11 @@ function generateTriggerPerformFn(params) {
695
778
  case "standard":
696
779
  return (0, perform_1.createCNIPerform)({ componentRegistry, onTrigger });
697
780
  case "component-ref":
698
- return (0, perform_1.createCNIComponentRefPerform)({ componentRegistry, componentRef, onTrigger });
781
+ return (0, perform_1.createCNIComponentRefPerform)({
782
+ componentRegistry,
783
+ componentRef,
784
+ onTrigger,
785
+ });
699
786
  default:
700
787
  throw new Error(`Invalid trigger configuration detected: ${JSON.stringify(params, null, 2)}`);
701
788
  }
@@ -751,7 +838,9 @@ const convertOnExecution = (onExecution, componentRegistry) => (context, params)
751
838
  });
752
839
  /** Creates the structure necessary to import a Component as part of a
753
840
  * Code Native integration. */
754
- const codeNativeIntegrationComponent = ({ name, iconPath, description, flows = [], componentRegistry = {}, }, referenceKey, configVars) => {
841
+ const codeNativeIntegrationComponent = ({ name, iconPath, description, flows: rawFlows = [], componentRegistry = {}, }, referenceKey, configVars) => {
842
+ // Expand any batched `trigger` so the action/trigger reducers below see the flat shape.
843
+ const flows = rawFlows.map((flow) => normalizeBatchedFlow(flow));
755
844
  const convertedActions = flows.reduce((result, { name, onExecution }) => {
756
845
  const key = flowFunctionKey(name, "onExecution");
757
846
  return Object.assign(Object.assign({}, result), { [key]: {
@@ -764,7 +853,12 @@ const codeNativeIntegrationComponent = ({ name, iconPath, description, flows = [
764
853
  inputs: [],
765
854
  } });
766
855
  }, {});
767
- const convertedTriggers = flows.reduce((result, { name, onTrigger, onInstanceDeploy, onInstanceDelete, webhookLifecycleHandlers, schedule, triggerType, }) => {
856
+ const convertedTriggers = flows.reduce((result, flow) => {
857
+ var _a;
858
+ const { name, onTrigger, onInstanceDeploy, onInstanceDelete, webhookLifecycleHandlers, schedule, triggerType, onDeployTrigger, } = flow;
859
+ // `batchConfig`/`triggerResolver`/`onDeployResolver` are wire-only fields synthesized by
860
+ // `normalizeBatchedFlow`; they aren't on the author-facing `Flow` type, so read via cast.
861
+ const { batchConfig, triggerResolver, onDeployResolver } = flow;
768
862
  if (!flowUsesWrapperTrigger({
769
863
  onTrigger,
770
864
  onInstanceDelete,
@@ -799,26 +893,45 @@ const codeNativeIntegrationComponent = ({ name, iconPath, description, flows = [
799
893
  const deployFn = generateTriggerEventWrapperFn(ref, onTrigger, "onInstanceDeploy", componentRegistry, onInstanceDeploy);
800
894
  const webhookCreateFn = generateTriggerEventWrapperFn(ref, onTrigger, "webhookCreate", componentRegistry, webhookLifecycleHandlers === null || webhookLifecycleHandlers === void 0 ? void 0 : webhookLifecycleHandlers.create);
801
895
  const webhookDeleteFn = generateTriggerEventWrapperFn(ref, onTrigger, "webhookDelete", componentRegistry, webhookLifecycleHandlers === null || webhookLifecycleHandlers === void 0 ? void 0 : webhookLifecycleHandlers.delete);
802
- return Object.assign(Object.assign({}, result), { [key]: {
803
- key,
804
- display: {
896
+ return Object.assign(Object.assign({}, result), { [key]: Object.assign(Object.assign(Object.assign(Object.assign({ key, display: {
805
897
  label: `${name} - onTrigger`,
806
898
  description: "The function that will be executed by the flow to return an HTTP response.",
807
- },
808
- perform: performFn,
809
- onInstanceDeploy: deployFn,
810
- hasOnInstanceDeploy: !!deployFn,
811
- onInstanceDelete: deleteFn,
812
- hasOnInstanceDelete: !!deleteFn,
813
- webhookCreate: webhookCreateFn,
814
- hasWebhookCreateFunction: !!webhookCreateFn,
815
- webhookDelete: webhookDeleteFn,
816
- hasWebhookDeleteFunction: !!webhookDeleteFn,
817
- inputs: wrapperTriggerInputsFromReference(onTrigger, componentRegistry),
818
- scheduleSupport: triggerType === "polling" ? "required" : "valid",
819
- synchronousResponseSupport: "valid",
820
- isPollingTrigger: triggerType === "polling",
821
- } });
899
+ }, perform: performFn, onInstanceDeploy: deployFn, hasOnInstanceDeploy: !!deployFn, onInstanceDelete: deleteFn, hasOnInstanceDelete: !!deleteFn, webhookCreate: webhookCreateFn, hasWebhookCreateFunction: !!webhookCreateFn, webhookDelete: webhookDeleteFn, hasWebhookDeleteFunction: !!webhookDeleteFn, inputs: wrapperTriggerInputsFromReference(onTrigger, componentRegistry), scheduleSupport: triggerType === "polling" ? "required" : "valid", synchronousResponseSupport: "valid", isPollingTrigger: triggerType === "polling", triggerResolverSupport: triggerResolver ? "valid" : "invalid" }, (triggerResolver || onDeployResolver
900
+ ? Object.assign({ triggerResolverDefaultBatchSize: (_a = batchConfig === null || batchConfig === void 0 ? void 0 : batchConfig.batchSize) !== null && _a !== void 0 ? _a : 1 }, ((batchConfig === null || batchConfig === void 0 ? void 0 : batchConfig.concurrentBatchLimit) !== undefined
901
+ ? {
902
+ triggerResolverDefaultConcurrentBatchLimit: batchConfig.concurrentBatchLimit,
903
+ }
904
+ : {})) : {})), (triggerResolver
905
+ ? Object.assign(Object.assign({}, (triggerResolver.resolveItems
906
+ ? {
907
+ resolveTriggerItems: triggerResolver.resolveItems,
908
+ hasResolveTriggerItems: true,
909
+ }
910
+ : {})), (triggerResolver.getNextDiscoveryState
911
+ ? {
912
+ getNextDiscoveryState: triggerResolver.getNextDiscoveryState,
913
+ hasGetNextDiscoveryState: true,
914
+ }
915
+ : {})) : {})), (onDeployTrigger
916
+ ? {
917
+ onDeployPerform: (0, perform_1.createCNIPerform)({
918
+ componentRegistry,
919
+ onTrigger: onDeployTrigger,
920
+ }),
921
+ hasOnDeployPerform: true,
922
+ }
923
+ : {})), (onDeployResolver
924
+ ? Object.assign(Object.assign({}, (onDeployResolver.resolveItems
925
+ ? {
926
+ resolveOnDeployItems: onDeployResolver.resolveItems,
927
+ hasResolveOnDeployItems: true,
928
+ }
929
+ : {})), (onDeployResolver.getNextDiscoveryState
930
+ ? {
931
+ getOnDeployNextDiscoveryState: onDeployResolver.getNextDiscoveryState,
932
+ hasGetOnDeployNextDiscoveryState: true,
933
+ }
934
+ : {})) : {})) });
822
935
  }, {});
823
936
  const convertedDataSources = Object.entries(configVars).reduce((result, [key, configVar]) => {
824
937
  if (!(0, types_1.isDataSourceDefinitionConfigVar)(configVar)) {
@@ -112,8 +112,8 @@ interface HttpResponse {
112
112
  headers?: Record<string, string>;
113
113
  body?: string;
114
114
  }
115
- interface TriggerBaseResult {
116
- payload: TriggerPayload;
115
+ interface TriggerBaseResult<TPayload extends TriggerPayload = TriggerPayload> {
116
+ payload: TPayload;
117
117
  response?: HttpResponse;
118
118
  instanceState?: Record<string, unknown>;
119
119
  crossFlowState?: Record<string, unknown>;
@@ -122,12 +122,23 @@ interface TriggerBaseResult {
122
122
  failed?: boolean;
123
123
  error?: Record<string, unknown>;
124
124
  }
125
- interface TriggerBranchingResult extends TriggerBaseResult {
125
+ interface TriggerBranchingResult<TPayload extends TriggerPayload = TriggerPayload> extends TriggerBaseResult<TPayload> {
126
126
  branch: string;
127
127
  }
128
- export type TriggerResult = TriggerBranchingResult | TriggerBaseResult | undefined;
128
+ export type TriggerResult<TPayload extends TriggerPayload = TriggerPayload> = TriggerBranchingResult<TPayload> | TriggerBaseResult<TPayload> | undefined;
129
129
  export type TriggerEventFunctionResult = TriggerEventFunctionReturn | void;
130
130
  export type TriggerEventFunction = (context: ActionContext, params: Record<string, unknown>) => Promise<TriggerEventFunctionResult>;
131
+ /**
132
+ * Wire format the platform expects for a trigger. Note: function references
133
+ * (perform, resolveTriggerItems, getNextDiscoveryState, ...) don't survive JSON
134
+ * serialization, so each callback has a paired `hasXxx: boolean` flag the
135
+ * server reads to detect presence. Keep the flag and its callback in sync.
136
+ *
137
+ * The on-deploy fire is named asymmetrically by intent: CNI flow authors set
138
+ * `onDeployTrigger` (sibling to `onTrigger`), component-trigger authors set
139
+ * `onDeployPerform` (sibling to `perform`), and both flatten to
140
+ * `onDeployPerform` here on the wire.
141
+ */
131
142
  export interface Trigger<TInputs extends Inputs, TActionInputs extends Inputs, TConfigVars extends ConfigVarResultCollection = ConfigVarResultCollection, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerPerformResult<TAllowsBranching, TPayload> = TriggerPerformResult<TAllowsBranching, TPayload>> {
132
143
  key: string;
133
144
  display: DisplayDefinition & {
@@ -155,6 +166,23 @@ export interface Trigger<TInputs extends Inputs, TActionInputs extends Inputs, T
155
166
  hasWebhookDeleteFunction?: boolean;
156
167
  scheduleSupport: TriggerOptionChoice;
157
168
  synchronousResponseSupport: TriggerOptionChoice;
169
+ triggerResolverSupport?: TriggerOptionChoice;
170
+ /**
171
+ * The single default batch size shared by the trigger and on-deploy resolvers. The
172
+ * platform reads only this field for both paths; there is no separate on-deploy default.
173
+ */
174
+ triggerResolverDefaultBatchSize?: number;
175
+ triggerResolverDefaultConcurrentBatchLimit?: number;
176
+ resolveTriggerItems?: (context: ActionContext<TConfigVars>, result: TriggerBaseResult<TPayload>) => unknown[];
177
+ hasResolveTriggerItems?: boolean;
178
+ getNextDiscoveryState?: (context: ActionContext<TConfigVars>, result: TriggerBaseResult<TPayload>) => Record<string, unknown> | null;
179
+ hasGetNextDiscoveryState?: boolean;
180
+ onDeployPerform?: TriggerPerformFunction<TInputs, TConfigVars, TAllowsBranching, TResult> | PollingTriggerPerformFunction<TInputs, TActionInputs, TConfigVars, TPayload, TAllowsBranching, TResult> | CNIPollingPerformFunction<TInputs, TConfigVars, TPayload, TAllowsBranching> | ComponentRefTriggerPerformFunction<TInputs, TConfigVars>;
181
+ hasOnDeployPerform?: boolean;
182
+ resolveOnDeployItems?: (context: ActionContext<TConfigVars>, result: TriggerBaseResult<TPayload>) => unknown[];
183
+ hasResolveOnDeployItems?: boolean;
184
+ getOnDeployNextDiscoveryState?: (context: ActionContext<TConfigVars>, result: TriggerBaseResult<TPayload>) => Record<string, unknown> | null;
185
+ hasGetOnDeployNextDiscoveryState?: boolean;
158
186
  examplePayload?: unknown;
159
187
  isCommonTrigger?: boolean;
160
188
  isPollingTrigger?: boolean;
@@ -262,5 +290,8 @@ export interface Input {
262
290
  onPremiseControlled?: boolean;
263
291
  dataSource?: string;
264
292
  shown?: boolean;
293
+ /** Nested children. For `structuredObject`, the declared inputs; for
294
+ * `dynamicObject`, one `structuredObject` per configuration. */
295
+ inputs?: Input[];
265
296
  }
266
297
  export * from "./asyncContext";
package/dist/testing.d.ts CHANGED
@@ -217,7 +217,7 @@ type ToTestValues<TConfigVars extends ConfigVarResultCollection> = {
217
217
  * expect(result.data).toBeDefined();
218
218
  * });
219
219
  */
220
- export declare const invokeFlow: <TInputs extends Inputs, TActionInputs extends Inputs, TConfigVars extends ConfigVarResultCollection = ConfigVarResultCollection, TConfigVarValues extends TestConfigVarValues = ToTestValues<TConfigVars>, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends InvokeTriggerResult<TAllowsBranching, TPayload> = InvokeTriggerResult<TAllowsBranching, TPayload>>(flow: Flow<TInputs, TActionInputs, TPayload, TAllowsBranching, TResult>, { configVars, context, payload, }?: {
220
+ export declare const invokeFlow: <TInputs extends Inputs, TActionInputs extends Inputs, TConfigVars extends ConfigVarResultCollection = ConfigVarResultCollection, TConfigVarValues extends TestConfigVarValues = ToTestValues<TConfigVars>, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends InvokeTriggerResult<TAllowsBranching, TPayload> = InvokeTriggerResult<TAllowsBranching, TPayload>>(flow: Flow<TInputs, TActionInputs, TPayload, TAllowsBranching, TResult, any, any, any>, { configVars, context, payload, }?: {
221
221
  configVars?: TConfigVarValues;
222
222
  context?: Partial<ActionContext<TConfigVars>>;
223
223
  payload?: Partial<TriggerPayload>;
package/dist/testing.js CHANGED
@@ -408,7 +408,11 @@ const createConfigVars = (values) => {
408
408
  * expect(result.data).toBeDefined();
409
409
  * });
410
410
  */
411
- const invokeFlow = (flow_1, ...args_1) => __awaiter(void 0, [flow_1, ...args_1], void 0, function* (flow, { configVars, context, payload, } = {}) {
411
+ const invokeFlow = (flow_1, ...args_1) => __awaiter(void 0, [flow_1, ...args_1], void 0, function* (
412
+ // `any` for TItem/TDiscoveryState/TTriggerPayload: the tester accepts a flow with any
413
+ // resolver item and cursor typing; it drives the flow dynamically and does not rely on
414
+ // the precise `onExecution` param type.
415
+ flow, { configVars, context, payload, } = {}) {
412
416
  const realizedConfigVars = createConfigVars(configVars);
413
417
  const realizedContext = createActionContext(Object.assign(Object.assign({}, context), { configVars: realizedConfigVars }));
414
418
  const realizedPayload = Object.assign(Object.assign({}, (0, exports.defaultTriggerPayload)()), payload);
@@ -1,11 +1,40 @@
1
1
  import type { ConditionalExpression } from "./conditional-logic";
2
- import type { Connection, InputCleanFunction, InputFieldCollection, Inputs, KeyValuePair } from "./Inputs";
2
+ import type { Connection, DynamicObjectInputField, InputCleanFunction, InputFieldCollection, Inputs, KeyValuePair, StructuredObjectInputField } from "./Inputs";
3
+ /** Resolves a single InputFieldDefinition's runtime value type.
4
+ * - structuredObject: record of declared children's resolved value types.
5
+ * - dynamicObject: discriminated union keyed by the selected configuration,
6
+ * with the configuration's resolved inputs nested under `values` to avoid
7
+ * collisions with the `configuration` discriminant key.
8
+ * The depth caps (`LeafInputFieldDefinition`, `StructuredOrLeafInputFieldDefinition`)
9
+ * prevent unbounded recursion. */
10
+ type InputValue<T> = T extends StructuredObjectInputField ? {
11
+ [K in keyof T["inputs"]]: InputValue<T["inputs"][K]>;
12
+ } : T extends DynamicObjectInputField ? {
13
+ [C in keyof T["configurations"]]: {
14
+ configuration: C;
15
+ values: {
16
+ [K in keyof T["configurations"][C]["inputs"]]: InputValue<T["configurations"][C]["inputs"][K]>;
17
+ };
18
+ };
19
+ }[keyof T["configurations"]] : T extends {
20
+ clean: InputCleanFunction<any>;
21
+ } ? ReturnType<T["clean"]> : T extends {
22
+ type: "connection";
23
+ collection?: InputFieldCollection;
24
+ } ? ExtractValue<Connection, T["collection"]> : T extends {
25
+ type: "conditional";
26
+ collection?: InputFieldCollection;
27
+ } ? ExtractValue<ConditionalExpression, T["collection"]> : T extends {
28
+ default?: unknown;
29
+ collection?: InputFieldCollection;
30
+ } ? ExtractValue<T["default"], T["collection"]> : unknown;
3
31
  /**
4
32
  * Collection of input parameters.
5
33
  * Inputs can be static values, references to config variables, or
6
34
  * references to previous steps' outputs.
7
35
  */
8
36
  export type ActionInputParameters<TInputs extends Inputs> = {
9
- [Property in keyof TInputs]: TInputs[Property]["clean"] extends InputCleanFunction<any> ? ReturnType<TInputs[Property]["clean"]> : TInputs[Property]["type"] extends "connection" ? ExtractValue<Connection, TInputs[Property]["collection"]> : TInputs[Property]["type"] extends "conditional" ? ExtractValue<ConditionalExpression, TInputs[Property]["collection"]> : ExtractValue<TInputs[Property]["default"], TInputs[Property]["collection"]>;
37
+ [Property in keyof TInputs]: InputValue<TInputs[Property]>;
10
38
  };
11
39
  export type ExtractValue<TType, TCollection extends InputFieldCollection | undefined> = TCollection extends "keyvaluelist" ? KeyValuePair<TType>[] : TCollection extends "valuelist" ? TType[] : TType;
40
+ export {};
@@ -63,6 +63,8 @@ export type JSONForm = {
63
63
  };
64
64
  export type DynamicObjectSelection = string;
65
65
  export type DynamicFieldSelection = string;
66
+ export type StructuredObject = Record<string, unknown>;
67
+ export type DynamicObject = Record<string, unknown>;
66
68
  /** InputField type enumeration. */
67
69
  export type InputFieldType = InputFieldDefinition["type"];
68
70
  export declare const InputFieldDefaultMap: Record<InputFieldType, string | undefined>;
@@ -83,7 +85,7 @@ export type OnPremConnectionInput = {
83
85
  */
84
86
  onPremControlled: true;
85
87
  } & ConnectionInput;
86
- export type InputFieldDefinition = StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField | CodeInputField | ConditionalInputField | ConnectionInputField | ConnectionTemplateInputField | ObjectSelectionInputField | ObjectFieldMapInputField | JSONFormInputField | DynamicObjectSelectionInputField | DynamicFieldSelectionInputField | DateInputField | DateTimeInputField | FlowInputField;
88
+ export type InputFieldDefinition = StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField | CodeInputField | ConditionalInputField | ConnectionInputField | ConnectionTemplateInputField | ObjectSelectionInputField | ObjectFieldMapInputField | JSONFormInputField | DynamicObjectSelectionInputField | DynamicFieldSelectionInputField | DateInputField | DateTimeInputField | FlowInputField | StructuredObjectInputField | DynamicObjectInputField;
87
89
  export type InputCleanFunction<TValue, TResult = TValue> = (value: TValue) => TResult;
88
90
  interface BaseInputField {
89
91
  /** Name of this field to present in the UI. */
@@ -289,6 +291,50 @@ export type DateTimeInputField = BaseInputField & {
289
291
  /** Clean function. */
290
292
  clean?: InputCleanFunction<unknown>;
291
293
  } & CollectionOptions<string>;
294
+ /** `InputFieldDefinition` minus container input types and connection
295
+ * pickers. Connections resolve to config-var references outside the
296
+ * parent's value tree, so they're only valid at the top level — never as
297
+ * a child of a structuredObject or a dynamicObject configuration. */
298
+ export type LeafInputFieldDefinition = Exclude<InputFieldDefinition, StructuredObjectInputField | DynamicObjectInputField | ConnectionInputField | ConnectionTemplateInputField>;
299
+ /** `LeafInputFieldDefinition` plus `StructuredObjectInputField`; used
300
+ * inside a dynamicObject's `configurations.<key>.inputs` to allow leaves
301
+ * and structuredObject children while still rejecting nested
302
+ * dynamicObjects and connection pickers. */
303
+ export type StructuredOrLeafInputFieldDefinition = LeafInputFieldDefinition | StructuredObjectInputField;
304
+ /** Groups related primitive inputs under a single named container.
305
+ * Nesting is capped at one level. Connection pickers are rejected as
306
+ * children — they may only appear at the top level. */
307
+ export type StructuredObjectInputField = Omit<BaseInputField, "dataSource" | "example" | "placeholder" | "required"> & {
308
+ /** Data type the input will collect. */
309
+ type: "structuredObject";
310
+ /** Nested input fields keyed by their local key. */
311
+ inputs: Record<string, LeafInputFieldDefinition>;
312
+ };
313
+ /** A single configuration within a dynamicObject. Each configuration declares
314
+ * a labeled set of inputs that become available when this configuration is
315
+ * selected at runtime. */
316
+ export interface DynamicObjectConfiguration {
317
+ /** Name of this configuration to present in the UI. */
318
+ label: {
319
+ key: string;
320
+ value: string;
321
+ } | string;
322
+ /** Additional text to give guidance to the user when this configuration is selected. */
323
+ comments?: string;
324
+ /** Inputs that become available when this configuration is selected. */
325
+ inputs: Record<string, StructuredOrLeafInputFieldDefinition>;
326
+ }
327
+ /** Presents a discriminated set of input groups; the user picks a configuration
328
+ * at integration-build time and that configuration's inputs become available.
329
+ * Nesting is capped: configurations may contain structuredObject children
330
+ * (depth-1) but never another dynamicObject. */
331
+ export type DynamicObjectInputField = Omit<BaseInputField, "dataSource" | "example" | "placeholder"> & {
332
+ /** Data type the input will collect. */
333
+ type: "dynamicObject";
334
+ /** Available configurations keyed by their local key (used as the
335
+ * runtime discriminant). */
336
+ configurations: Record<string, DynamicObjectConfiguration>;
337
+ };
292
338
  /** Defines a single Choice option for a InputField. */
293
339
  export interface InputFieldChoice {
294
340
  /** Label to display for this Choice. */
@@ -19,4 +19,6 @@ exports.InputFieldDefaultMap = {
19
19
  timestamp: "",
20
20
  flow: "",
21
21
  template: "",
22
+ structuredObject: undefined,
23
+ dynamicObject: undefined,
22
24
  };