@prismatic-io/spectral 10.20.0 → 10.21.1-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.
@@ -134,15 +134,10 @@ const fetchComponentDataForManifest = (_a) => __awaiter(void 0, [_a], void 0, fu
134
134
  };
135
135
  }
136
136
  else {
137
- actions[node.key] = {
138
- key: node.key,
139
- display: {
137
+ actions[node.key] = Object.assign(Object.assign({ key: node.key, display: {
140
138
  label: node.label,
141
139
  description: node.description,
142
- },
143
- inputs: transformInputNodes(node.inputs.nodes),
144
- examplePayload: node.examplePayload,
145
- };
140
+ }, inputs: transformInputNodes(node.inputs.nodes), examplePayload: node.examplePayload }, (node.examplePerformSafety ? { examplePerformSafety: node.examplePerformSafety } : {})), (node.performSafety ? { performSafety: node.performSafety } : {}));
146
141
  }
147
142
  });
148
143
  const connections = component.connections.nodes.map((node) => {
@@ -245,6 +240,8 @@ function getComponentActions(componentId, prismaticUrl, accessToken) {
245
240
  }
246
241
  }
247
242
  examplePayload
243
+ examplePerformSafety
244
+ performSafety
248
245
  }
249
246
  pageInfo {
250
247
  hasNextPage
@@ -1,5 +1,6 @@
1
1
  import type { Action, Component, DataSource, Trigger, TriggerPayload } from "../../serverTypes";
2
2
  import type { ConfigVarResultCollection, Inputs } from "../../types";
3
+ import type { PerformSafety } from "../../types/ActionDefinition";
3
4
  import type { TriggerResult } from "../../types/TriggerResult";
4
5
  export interface ComponentNode {
5
6
  id: string;
@@ -28,6 +29,8 @@ export interface ActionNode {
28
29
  nodes: InputNode[];
29
30
  };
30
31
  examplePayload: string | null;
32
+ examplePerformSafety: PerformSafety | null;
33
+ performSafety: PerformSafety | null;
31
34
  }
32
35
  export interface ConnectionNode {
33
36
  key: string;
@@ -47,7 +50,10 @@ export interface InputNode {
47
50
  shown: boolean;
48
51
  onPremiseControlled: boolean;
49
52
  }
50
- export type FormattedAction = Pick<Action, "key" | "display" | "inputs" | "examplePayload">;
53
+ export type FormattedAction = Pick<Action, "key" | "display" | "inputs" | "examplePayload" | "examplePerformSafety" | "performSafety"> & {
54
+ /** Emitted verbatim into the generated manifest; shape mirrors `examplePayload`. */
55
+ outputSchema?: unknown;
56
+ };
51
57
  export type FormattedTrigger<TInputs extends Inputs, TActionInputs extends Inputs, TConfigVars extends ConfigVarResultCollection = ConfigVarResultCollection, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>> = Pick<Trigger<TInputs, TActionInputs, TConfigVars, TPayload, TAllowsBranching, TResult>, "key" | "display" | "inputs">;
52
58
  export type FormattedDataSource = Pick<DataSource, "key" | "display" | "inputs" | "dataSourceType" | "examplePayload">;
53
59
  export type ComponentForManifest<TInputs extends Inputs, TActionInputs extends Inputs, TConfigVars extends ConfigVarResultCollection = ConfigVarResultCollection, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>> = Pick<Component<TInputs, TActionInputs, TConfigVars, TPayload, TAllowsBranching, TResult>, "key" | "public" | "display" | "connections"> & {
@@ -44,7 +44,9 @@ const createActions = (_a) => __awaiter(void 0, [_a], void 0, function* ({ compo
44
44
  });
45
45
  const imports = (0, getImports_1.getImports)({ inputs });
46
46
  return yield renderAction({
47
- action: Object.assign(Object.assign({ typeInterface: (0, createTypeInterface_1.createTypeInterface)((_b = action.key) !== null && _b !== void 0 ? _b : actionKey), import: (0, createImport_1.createImport)((_c = action.key) !== null && _c !== void 0 ? _c : actionKey), key: action.key || actionKey, label: action.display.label, description: action.display.description, inputs }, (action.examplePayload ? { examplePayload: action.examplePayload } : {})), { componentKey: component.key }),
47
+ action: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ typeInterface: (0, createTypeInterface_1.createTypeInterface)((_b = action.key) !== null && _b !== void 0 ? _b : actionKey), import: (0, createImport_1.createImport)((_c = action.key) !== null && _c !== void 0 ? _c : actionKey), key: action.key || actionKey, label: action.display.label, description: action.display.description, inputs }, (action.examplePayload ? { examplePayload: action.examplePayload } : {})), (action.outputSchema ? { outputSchema: action.outputSchema } : {})), (action.examplePerformSafety
48
+ ? { examplePerformSafety: action.examplePerformSafety }
49
+ : {})), (action.performSafety ? { performSafety: action.performSafety } : {})), { componentKey: component.key }),
48
50
  imports,
49
51
  dryRun,
50
52
  verbose,
@@ -25,4 +25,13 @@ export const <%= action.import %> = {
25
25
  <%_ if (action.examplePayload) { -%>
26
26
  examplePayload: <%- typeof action.examplePayload === 'string' ? action.examplePayload : JSON.stringify(action.examplePayload, null, 2) %>,
27
27
  <%_ } -%>
28
+ <%_ if (action.outputSchema) { -%>
29
+ outputSchema: <%- typeof action.outputSchema === 'string' ? action.outputSchema : JSON.stringify(action.outputSchema, null, 2) %>,
30
+ <%_ } -%>
31
+ <%_ if (action.examplePerformSafety) { -%>
32
+ examplePerformSafety: "<%= action.examplePerformSafety %>",
33
+ <%_ } -%>
34
+ <%_ if (action.performSafety) { -%>
35
+ performSafety: "<%= action.performSafety %>",
36
+ <%_ } -%>
28
37
  } as const;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { convertComponent } from "./serverTypes/convertComponent";
7
7
  import { convertIntegration } from "./serverTypes/convertIntegration";
8
- import type { ActionDefinition, ActionPerformReturn, BatchTrigger, ComponentDefinition, ComponentManifest, ConfigPage, ConfigVarResultCollection, ConnectionConfigVar, CustomerActivatedConnectionConfigVar, DataSourceConfigVar, DataSourceDefinition, DataSourceType, DefaultConnectionDefinition, DynamicObjectInputField, Flow, InputFieldDefinition, Inputs, IntegrationDefinition, OAuth2ConnectionDefinition, OnPremConnectionDefinition, OrganizationActivatedConnectionConfigVar, StandardConfigVar, StructuredObjectInputField, TriggerDefinition, TriggerPayload, TriggerResult } from "./types";
8
+ import type { ActionDefinition, ActionPerformReturn, BatchTrigger, ComponentDefinition, ComponentManifest, ConfigPage, ConfigVarResultCollection, ConnectionConfigVar, CustomerActivatedConnectionConfigVar, DataSourceConfigVar, DataSourceDefinition, DataSourceType, DefaultConnectionDefinition, DynamicObjectInputField, Flow, InputFieldDefinition, Inputs, IntegrationDefinition, OAuth2ConnectionDefinition, OnPremConnectionDefinition, OrganizationActivatedConnectionConfigVar, OutputSchema, StandardConfigVar, StructuredObjectInputField, TriggerDefinition, TriggerPayload, TriggerResult } from "./types";
9
9
  import type { PollingTriggerDefinition } from "./types/PollingTriggerDefinition";
10
10
  /**
11
11
  * This function creates a code-native integration object that can be
@@ -383,6 +383,38 @@ export declare const component: <TPublic extends boolean, TKey extends string>(d
383
383
  * });
384
384
  */
385
385
  export declare const action: <TInputs extends Inputs, TConfigVars extends ConfigVarResultCollection, TAllowsBranching extends boolean, TReturn extends ActionPerformReturn<TAllowsBranching, unknown>>(definition: ActionDefinition<TInputs, TConfigVars, TAllowsBranching, TReturn>) => ActionDefinition<TInputs, TConfigVars, TAllowsBranching, TReturn>;
386
+ /**
387
+ * Declares the output schema for an action and preserves its literal types,
388
+ * so authors don't need a trailing `as const` (or `satisfies OutputSchema`)
389
+ * to keep the `type` discriminant from widening to `string`.
390
+ *
391
+ * Wrapping the schema in this helper lets it be hoisted into a standalone
392
+ * variable and still satisfy the {@link OutputSchema} discriminated union:
393
+ *
394
+ * @example
395
+ * import { action, outputSchema } from "@prismatic-io/spectral";
396
+ *
397
+ * // Hoisted out of the action — no `as const` needed.
398
+ * const listItemsOutput = outputSchema({
399
+ * type: "actionOutput",
400
+ * schema: {
401
+ * type: "object",
402
+ * properties: { items: { type: "array" } },
403
+ * },
404
+ * });
405
+ *
406
+ * export const listItems = action({
407
+ * display: { label: "List Items", description: "..." },
408
+ * inputs: {},
409
+ * perform: async () => ({ data: { items: [] } }),
410
+ * outputSchema: listItemsOutput,
411
+ * });
412
+ *
413
+ * @param definition An {@link OutputSchema} object — either an `actionOutput`
414
+ * single-payload schema or a `branchingOutput` per-branch map.
415
+ * @returns The same object, typed with its literal discriminant preserved.
416
+ */
417
+ export declare const outputSchema: <const TOutputSchema extends OutputSchema>(definition: TOutputSchema) => TOutputSchema;
386
418
  /**
387
419
  * This function creates a trigger object that can be referenced
388
420
  * by a custom component. It helps ensure that the shape of the
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
23
  };
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.util = exports.testing = exports.componentManifests = exports.oauth2Connection = exports.onPremConnection = exports.connection = exports.dynamicObjectInput = exports.structuredObjectInput = exports.input = exports.dataSource = exports.pollingTrigger = exports.trigger = exports.action = exports.component = exports.componentManifest = exports.organizationActivatedConnection = exports.customerActivatedConnection = exports.connectionConfigVar = exports.dataSourceConfigVar = exports.configVar = exports.configPage = exports.batchFlowTrigger = exports.flow = exports.integration = void 0;
25
+ exports.util = exports.testing = exports.componentManifests = exports.oauth2Connection = exports.onPremConnection = exports.connection = exports.dynamicObjectInput = exports.structuredObjectInput = exports.input = exports.dataSource = exports.pollingTrigger = exports.trigger = exports.outputSchema = exports.action = exports.component = exports.componentManifest = exports.organizationActivatedConnection = exports.customerActivatedConnection = exports.connectionConfigVar = exports.dataSourceConfigVar = exports.configVar = exports.configPage = exports.batchFlowTrigger = exports.flow = exports.integration = void 0;
26
26
  const serverTypes_1 = require("./serverTypes");
27
27
  const convertComponent_1 = require("./serverTypes/convertComponent");
28
28
  const convertIntegration_1 = require("./serverTypes/convertIntegration");
@@ -426,6 +426,39 @@ exports.component = component;
426
426
  */
427
427
  const action = (definition) => definition;
428
428
  exports.action = action;
429
+ /**
430
+ * Declares the output schema for an action and preserves its literal types,
431
+ * so authors don't need a trailing `as const` (or `satisfies OutputSchema`)
432
+ * to keep the `type` discriminant from widening to `string`.
433
+ *
434
+ * Wrapping the schema in this helper lets it be hoisted into a standalone
435
+ * variable and still satisfy the {@link OutputSchema} discriminated union:
436
+ *
437
+ * @example
438
+ * import { action, outputSchema } from "@prismatic-io/spectral";
439
+ *
440
+ * // Hoisted out of the action — no `as const` needed.
441
+ * const listItemsOutput = outputSchema({
442
+ * type: "actionOutput",
443
+ * schema: {
444
+ * type: "object",
445
+ * properties: { items: { type: "array" } },
446
+ * },
447
+ * });
448
+ *
449
+ * export const listItems = action({
450
+ * display: { label: "List Items", description: "..." },
451
+ * inputs: {},
452
+ * perform: async () => ({ data: { items: [] } }),
453
+ * outputSchema: listItemsOutput,
454
+ * });
455
+ *
456
+ * @param definition An {@link OutputSchema} object — either an `actionOutput`
457
+ * single-payload schema or a `branchingOutput` per-branch map.
458
+ * @returns The same object, typed with its literal discriminant preserved.
459
+ */
460
+ const outputSchema = (definition) => definition;
461
+ exports.outputSchema = outputSchema;
429
462
  /**
430
463
  * This function creates a trigger object that can be referenced
431
464
  * by a custom component. It helps ensure that the shape of the
@@ -1,6 +1,6 @@
1
- import { type ComponentDefinition, type ComponentHooks, type ConfigVarResultCollection, type ConnectionDefinition, type ConnectionInput, type ConnectionTemplateInputField, type InputFieldDefinition, type Inputs, type OnPremConnectionInput, type TriggerDefinition, type TriggerPayload, type TriggerResult } from "../types";
1
+ import { type ActionDefinition, type ComponentDefinition, type ComponentHooks, type ConfigVarResultCollection, type ConnectionDefinition, type ConnectionInput, type ConnectionTemplateInputField, type InputFieldDefinition, type Inputs, type OnPremConnectionInput, type TriggerDefinition, type TriggerPayload, type TriggerResult } from "../types";
2
2
  import { type PollingTriggerDefinition } from "../types/PollingTriggerDefinition";
3
- import type { Component as ServerComponent, Connection as ServerConnection, Input as ServerInput, Trigger as ServerTrigger } from ".";
3
+ import type { Action as ServerAction, Component as ServerComponent, Connection as ServerConnection, Input as ServerInput, Trigger as ServerTrigger } from ".";
4
4
  import { type CleanFn } from "./perform";
5
5
  /** Auto-generated cleaner for structuredObject/dynamicObject containers.
6
6
  * Recursively delegates to each child's clean function. Developers do not
@@ -29,6 +29,7 @@ export declare const _isValidTemplateValue: (template: string, inputs: {
29
29
  export declare const convertTemplateInput: (key: string, { templateValue, label, ...rest }: ConnectionTemplateInputField, inputs: {
30
30
  [key: string]: ConnectionInput | ConnectionTemplateInputField;
31
31
  }) => ServerInput;
32
+ export declare const convertAction: (actionKey: string, { inputs, perform, outputSchema, examplePerform, ...action }: ActionDefinition<Inputs, any, boolean, any>, hooks?: ComponentHooks) => ServerAction;
32
33
  export declare const convertTrigger: <TInputs extends Inputs, TActionInputs extends Inputs, TConfigVars extends ConfigVarResultCollection = ConfigVarResultCollection, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>>(triggerKey: string, trigger: TriggerDefinition<any> | PollingTriggerDefinition<any, ConfigVarResultCollection, TriggerPayload, boolean, any, any>, hooks?: ComponentHooks) => ServerTrigger<TInputs, TActionInputs, TConfigVars, TPayload, TAllowsBranching, TResult>;
33
34
  export declare const convertConnection: ({ inputs, ...connection }: ConnectionDefinition) => ServerConnection;
34
35
  export declare const convertComponent: <TPublic extends boolean, TKey extends string, TInputs extends Inputs, TActionInputs extends Inputs, TConfigVars extends ConfigVarResultCollection = ConfigVarResultCollection, TPayload extends TriggerPayload = TriggerPayload, TAllowsBranching extends boolean = boolean, TResult extends TriggerResult<TAllowsBranching, TPayload> = TriggerResult<TAllowsBranching, TPayload>>({ connections, actions, triggers, dataSources, hooks, ...definition }: ComponentDefinition<TPublic, TKey>) => ServerComponent<TInputs, TActionInputs, TConfigVars, TPayload, TAllowsBranching, TResult>;
@@ -14,7 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.convertComponent = exports.convertConnection = exports.convertTrigger = exports.convertTemplateInput = exports._isValidTemplateValue = exports.convertInput = exports.validateConcurrentBatchLimit = exports.validateBatchSize = exports.cleanerFor = void 0;
17
+ exports.convertComponent = exports.convertConnection = exports.convertTrigger = exports.convertAction = exports.convertTemplateInput = exports._isValidTemplateValue = exports.convertInput = exports.validateConcurrentBatchLimit = exports.validateBatchSize = exports.cleanerFor = void 0;
18
18
  const omit_1 = __importDefault(require("lodash/omit"));
19
19
  const types_1 = require("../types");
20
20
  const PollingTriggerDefinition_1 = require("../types/PollingTriggerDefinition");
@@ -213,15 +213,35 @@ const convertTemplateInput = (key, _a, inputs) => {
213
213
  return Object.assign(Object.assign({}, (0, omit_1.default)(rest, ["permissionAndVisibilityType", "visibleToOrgDeployer", "writeOnly"])), { key, type: "template", default: templateValue !== null && templateValue !== void 0 ? templateValue : "", label: typeof label === "string" ? label : label.value, shown: false });
214
214
  };
215
215
  exports.convertTemplateInput = convertTemplateInput;
216
+ const convertOutputSchema = (outputSchema) => {
217
+ if (outputSchema.type === "actionOutput") {
218
+ return { type: "actionOutput", schema: JSON.stringify(outputSchema.schema) };
219
+ }
220
+ return {
221
+ type: "branchingOutput",
222
+ branchSchemas: Object.entries(outputSchema.branchSchemas).map(([name, schema]) => ({
223
+ name,
224
+ schema: JSON.stringify(schema),
225
+ })),
226
+ };
227
+ };
216
228
  const convertAction = (actionKey, _a, hooks) => {
217
- var { inputs = {}, perform } = _a, action = __rest(_a, ["inputs", "perform"]);
229
+ var { inputs = {}, perform, outputSchema, examplePerform } = _a, action = __rest(_a, ["inputs", "perform", "outputSchema", "examplePerform"]);
218
230
  const convertedInputs = Object.entries(inputs).map(([key, value]) => (0, exports.convertInput)(key, value));
219
231
  const inputCleaners = Object.entries(inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: (0, exports.cleanerFor)(value) })), {});
220
- return Object.assign(Object.assign({}, action), { key: actionKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
232
+ return Object.assign(Object.assign(Object.assign(Object.assign({}, action), { key: actionKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
221
233
  inputCleaners,
222
234
  errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
223
- }) });
235
+ }) }), (outputSchema ? { outputSchema: convertOutputSchema(outputSchema) } : {})), (examplePerform
236
+ ? {
237
+ examplePerform: (0, perform_1.createPerform)(examplePerform, {
238
+ inputCleaners,
239
+ errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
240
+ }),
241
+ }
242
+ : {}));
224
243
  };
244
+ exports.convertAction = convertAction;
225
245
  const convertTrigger = (triggerKey,
226
246
  // `any` is load-bearing: the user-facing TriggerDefinition / PollingTriggerDefinition
227
247
  // type their event-function fields (onInstanceDeploy, webhookLifecycleHandlers, etc.) over
@@ -354,7 +374,7 @@ const convertConnection = (_a) => {
354
374
  exports.convertConnection = convertConnection;
355
375
  const convertComponent = (_a) => {
356
376
  var { connections = [], actions = {}, triggers = {}, dataSources = {}, hooks } = _a, definition = __rest(_a, ["connections", "actions", "triggers", "dataSources", "hooks"]);
357
- const convertedActions = Object.entries(actions).reduce((result, [actionKey, action]) => (Object.assign(Object.assign({}, result), { [actionKey]: convertAction(actionKey, action, hooks) })), {});
377
+ const convertedActions = Object.entries(actions).reduce((result, [actionKey, action]) => (Object.assign(Object.assign({}, result), { [actionKey]: (0, exports.convertAction)(actionKey, action, hooks) })), {});
358
378
  const convertedTriggers = Object.entries(triggers).reduce((result, [triggerKey, trigger]) => (Object.assign(Object.assign({}, result), { [triggerKey]: (0, exports.convertTrigger)(triggerKey, trigger, hooks) })), {});
359
379
  const convertedDataSources = Object.entries(dataSources).reduce((result, [dataSourceKey, dataSource]) => (Object.assign(Object.assign({}, result), { [dataSourceKey]: convertDataSource(dataSourceKey, dataSource, hooks) })), {});
360
380
  return Object.assign(Object.assign({}, definition), { connections: connections.map(exports.convertConnection), actions: convertedActions, triggers: convertedTriggers, dataSources: convertedDataSources });
@@ -1,4 +1,4 @@
1
- import type { ComponentManifest, ConfigVarResultCollection, CustomerAttributes, DataSourceResultType, DataSourceType, DebugContext, ExecutionFrame, FlowAttributes, FlowInvoker, FlowSchemas, Inputs, InstanceAttributes, IntegrationAttributes, PollingTriggerPerformFunction, TriggerEventFunctionReturn, TriggerPerformFunction, TriggerResult as TriggerPerformResult, UserAttributes } from "../types";
1
+ import type { ComponentManifest, ConfigVarResultCollection, CustomerAttributes, DataSourceResultType, DataSourceType, DebugContext, ExecutionFrame, FlowAttributes, FlowInvoker, FlowSchemas, Inputs, InstanceAttributes, IntegrationAttributes, PerformSafety, PollingTriggerPerformFunction, TriggerEventFunctionReturn, TriggerPerformFunction, TriggerResult as TriggerPerformResult, UserAttributes } from "../types";
2
2
  import type { CNIPollingPerformFunction, ComponentRefTriggerPerformFunction } from "./triggerTypes";
3
3
  interface DisplayDefinition {
4
4
  label: string;
@@ -40,7 +40,28 @@ export interface Action {
40
40
  dynamicBranchInput?: string;
41
41
  perform: ActionPerformFunction;
42
42
  examplePayload?: unknown;
43
+ /**
44
+ * The on-the-wire form of an action's `outputSchema`, as accepted by the
45
+ * `PublishComponent` mutation. JSON Schemas are serialized to strings and the
46
+ * branching variant's per-branch map is flattened to a `{ name, schema }`
47
+ * list (GraphQL input has no map type). Produced by `convertOutputSchema`
48
+ * from the author-facing `OutputSchema`.
49
+ */
50
+ outputSchema?: ServerOutputSchema;
51
+ examplePerform?: ActionPerformFunction;
52
+ examplePerformSafety?: PerformSafety;
53
+ performSafety?: PerformSafety;
43
54
  }
55
+ export type ServerOutputSchema = {
56
+ type: "actionOutput";
57
+ schema: string;
58
+ } | {
59
+ type: "branchingOutput";
60
+ branchSchemas: Array<{
61
+ name: string;
62
+ schema: string;
63
+ }>;
64
+ };
44
65
  export type ActionLoggerFunction = (...args: unknown[]) => void;
45
66
  export interface ActionLogger {
46
67
  metric: ActionLoggerFunction;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ /**
16
+ * Verifies what spectral serializes for the inline-action example-perform fields
17
+ * on publish — the converted server component `prism component publish` sends.
18
+ *
19
+ * Scope is conversion output only: which fields land on the wire, with what values.
20
+ * It does not verify runtime dispatch (SAFE vs. UNSAFE vs. NOT_ALLOWED choosing
21
+ * which perform runs) — the safety flags are inert metadata spectral passes through
22
+ * verbatim, and the runner decides at execution time.
23
+ */
24
+ const ejs_1 = require("ejs");
25
+ const path_1 = __importDefault(require("path"));
26
+ const vitest_1 = require("vitest");
27
+ const helpers_1 = require("../generators/componentManifest/helpers");
28
+ const index_1 = require("../index");
29
+ const display = (label) => ({ label, description: label });
30
+ // Three input shapes exercised on every permutation.
31
+ const connectionInput = (0, index_1.input)({ label: "Connection", type: "connection", required: true });
32
+ const structuredInput = (0, index_1.structuredObjectInput)({
33
+ label: "Name",
34
+ inputs: {
35
+ first: (0, index_1.input)({ type: "string", label: "First", required: true }),
36
+ last: (0, index_1.input)({ type: "string", label: "Last", required: true }),
37
+ },
38
+ });
39
+ const collectionInput = (0, index_1.input)({ label: "Tags", type: "string", collection: "valuelist" });
40
+ const sharedInputs = {
41
+ connection: connectionInput,
42
+ name: structuredInput,
43
+ tags: collectionInput,
44
+ };
45
+ const noop = () => __awaiter(void 0, void 0, void 0, function* () { return ({ data: null }); });
46
+ const echo = (_ctx, params) => __awaiter(void 0, void 0, void 0, function* () { return ({ data: params }); });
47
+ // Action permutations.
48
+ const testComponent = (0, index_1.component)({
49
+ key: "inline-action-testbed",
50
+ public: false,
51
+ display: Object.assign(Object.assign({}, display("Inline Action Testbed")), { iconPath: "icon.png" }),
52
+ actions: {
53
+ // A — no inline-calling fields.
54
+ plainAction: (0, index_1.action)({
55
+ display: display("Plain Action"),
56
+ inputs: sharedInputs,
57
+ perform: noop,
58
+ }),
59
+ // B — example perform + its safety flag.
60
+ examplePerformAction: (0, index_1.action)({
61
+ display: display("Example Perform Action"),
62
+ inputs: sharedInputs,
63
+ perform: noop,
64
+ examplePerform: echo,
65
+ examplePerformSafety: index_1.PerformSafety.SAFE,
66
+ }),
67
+ // C — real perform marked runnable.
68
+ runnablePerformAction: (0, index_1.action)({
69
+ display: display("Runnable Perform Action"),
70
+ inputs: sharedInputs,
71
+ perform: noop,
72
+ performSafety: index_1.PerformSafety.UNSAFE,
73
+ }),
74
+ // D — real perform marked not runnable.
75
+ notAllowedPerformAction: (0, index_1.action)({
76
+ display: display("Not Allowed Perform Action"),
77
+ inputs: sharedInputs,
78
+ perform: noop,
79
+ performSafety: index_1.PerformSafety.NOT_ALLOWED,
80
+ }),
81
+ },
82
+ });
83
+ // Converted actions are keyed by action key.
84
+ const actionsByKey = testComponent.actions;
85
+ (0, vitest_1.describe)("inline action calling: publish-wire conversion output", () => {
86
+ (0, vitest_1.it)("A — plain action: no inline-calling fields leak onto the wire", () => {
87
+ const a = actionsByKey.plainAction;
88
+ (0, vitest_1.expect)("examplePerform" in a).toBe(false);
89
+ (0, vitest_1.expect)(a.examplePerformSafety).toBeUndefined();
90
+ (0, vitest_1.expect)(a.performSafety).toBeUndefined();
91
+ });
92
+ (0, vitest_1.it)("B — example perform is wrapped (invokable) and its safety flag is carried", () => __awaiter(void 0, void 0, void 0, function* () {
93
+ var _a;
94
+ const a = actionsByKey.examplePerformAction;
95
+ (0, vitest_1.expect)(typeof a.examplePerform).toBe("function");
96
+ (0, vitest_1.expect)(a.examplePerformSafety).toBe("SAFE");
97
+ // Only the field the author set is carried; no performSafety leaks in.
98
+ (0, vitest_1.expect)(a.performSafety).toBeUndefined();
99
+ // Wrapped fn is invokable and passes params through.
100
+ const result = yield ((_a = a.examplePerform) === null || _a === void 0 ? void 0 : _a.call(a, {}, { tags: ["x"] }));
101
+ (0, vitest_1.expect)(result.data.tags).toStrictEqual(["x"]);
102
+ }));
103
+ (0, vitest_1.it)("C — real-perform UNSAFE flag carried; no separate example perform", () => {
104
+ const a = actionsByKey.runnablePerformAction;
105
+ (0, vitest_1.expect)(a.performSafety).toBe("UNSAFE");
106
+ (0, vitest_1.expect)("examplePerform" in a).toBe(false);
107
+ (0, vitest_1.expect)(a.examplePerformSafety).toBeUndefined();
108
+ });
109
+ (0, vitest_1.it)("D — real-perform NOT_ALLOWED flag carried verbatim; no example perform", () => {
110
+ const a = actionsByKey.notAllowedPerformAction;
111
+ (0, vitest_1.expect)(a.performSafety).toBe("NOT_ALLOWED");
112
+ (0, vitest_1.expect)("examplePerform" in a).toBe(false);
113
+ (0, vitest_1.expect)(a.examplePerformSafety).toBeUndefined();
114
+ });
115
+ (0, vitest_1.it)("the three input shapes survive conversion on every permutation", () => {
116
+ for (const key of [
117
+ "plainAction",
118
+ "examplePerformAction",
119
+ "runnablePerformAction",
120
+ "notAllowedPerformAction",
121
+ ]) {
122
+ const inputs = actionsByKey[key].inputs;
123
+ const byKey = Object.fromEntries(inputs.map((i) => [i.key, i]));
124
+ (0, vitest_1.expect)(byKey.connection.type).toBe("connection");
125
+ (0, vitest_1.expect)(byKey.name.type).toBe("structuredObject");
126
+ (0, vitest_1.expect)(byKey.name.inputs).toHaveLength(2); // nested children survived
127
+ (0, vitest_1.expect)(byKey.tags.collection).toBe("valuelist");
128
+ }
129
+ });
130
+ });
131
+ (0, vitest_1.describe)("inline action calling: component-manifest emit", () => {
132
+ const templatePath = path_1.default.join(__dirname, "../generators/componentManifest/templates/actions/action.ts.ejs");
133
+ const baseAction = {
134
+ typeInterface: "DoThing",
135
+ import: "doThing",
136
+ key: "doThing",
137
+ label: "Do Thing",
138
+ description: "Does a thing.",
139
+ inputs: [],
140
+ componentKey: "testbed",
141
+ };
142
+ const render = (extra) => (0, ejs_1.renderFile)(templatePath, { action: Object.assign(Object.assign({}, baseAction), extra), helpers: helpers_1.helpers, imports: {} });
143
+ (0, vitest_1.it)("emits both *Safety scalars when present", () => __awaiter(void 0, void 0, void 0, function* () {
144
+ const out = yield render({
145
+ examplePerformSafety: "SAFE",
146
+ performSafety: "UNSAFE",
147
+ });
148
+ (0, vitest_1.expect)(out).toContain('examplePerformSafety: "SAFE"');
149
+ (0, vitest_1.expect)(out).toContain('performSafety: "UNSAFE"');
150
+ }));
151
+ (0, vitest_1.it)("emits a NOT_ALLOWED performSafety scalar verbatim", () => __awaiter(void 0, void 0, void 0, function* () {
152
+ const out = yield render({ performSafety: "NOT_ALLOWED" });
153
+ (0, vitest_1.expect)(out).toContain('performSafety: "NOT_ALLOWED"');
154
+ }));
155
+ (0, vitest_1.it)("omits the *Safety scalars when absent (permutation A)", () => __awaiter(void 0, void 0, void 0, function* () {
156
+ const out = yield render({});
157
+ (0, vitest_1.expect)(out).not.toContain("examplePerformSafety");
158
+ (0, vitest_1.expect)(out).not.toContain("performSafety");
159
+ }));
160
+ (0, vitest_1.it)("never emits an examplePerform stub (invoked via the server action, not the manifest)", () => __awaiter(void 0, void 0, void 0, function* () {
161
+ const out = yield render({
162
+ examplePerformSafety: "SAFE",
163
+ performSafety: "UNSAFE",
164
+ });
165
+ (0, vitest_1.expect)(out).not.toContain("examplePerform:");
166
+ }));
167
+ });
@@ -3,6 +3,17 @@ import type { ActionPerformReturn } from "./ActionPerformReturn";
3
3
  import type { ComponentManifestAction } from "./ComponentManifest";
4
4
  import type { ActionDisplayDefinition } from "./DisplayDefinition";
5
5
  import type { ConfigVarResultCollection, Inputs } from "./Inputs";
6
+ import type { OutputSchema } from "./OutputSchema";
7
+ /**
8
+ * Whether a perform is safe to invoke inline (to populate reference data in the Prismatic UI):
9
+ * `SAFE` to run as-is, `UNSAFE` if running has side effects, `NOT_ALLOWED` to opt out.
10
+ */
11
+ export declare const PerformSafety: {
12
+ readonly SAFE: "SAFE";
13
+ readonly UNSAFE: "UNSAFE";
14
+ readonly NOT_ALLOWED: "NOT_ALLOWED";
15
+ };
16
+ export type PerformSafety = (typeof PerformSafety)[keyof typeof PerformSafety];
6
17
  /**
7
18
  * ActionDefinition is the type of the object that is passed in to `action` function to
8
19
  * define a component action. See
@@ -13,6 +24,9 @@ export interface ActionDefinition<TInputs extends Inputs = Inputs, TConfigVars e
13
24
  display: ActionDisplayDefinition;
14
25
  /** The function to perform when this action is invoked. */
15
26
  perform: ActionPerformFunction<TInputs, TConfigVars, Record<string, Record<string, ComponentManifestAction>>, TAllowsBranching, TReturn>;
27
+ examplePerform?: ActionPerformFunction<TInputs, TConfigVars, Record<string, Record<string, ComponentManifestAction>>, TAllowsBranching, TReturn>;
28
+ examplePerformSafety?: PerformSafety;
29
+ performSafety?: PerformSafety;
16
30
  /**
17
31
  * The inputs to present a low-code integration builder. Values of these inputs
18
32
  * are passed to the `perform` function when the action is invoked.
@@ -37,4 +51,18 @@ export interface ActionDefinition<TInputs extends Inputs = Inputs, TConfigVars e
37
51
  dynamicBranchInput?: string;
38
52
  /** An example of the payload output by this action. */
39
53
  examplePayload?: Awaited<ReturnType<this["perform"]>>;
54
+ /**
55
+ * Declares the shape of this action's output `data` as a JSON Schema, used by
56
+ * the Prismatic UI to let integration authors reference this step's output
57
+ * before a real execution has produced data. A discriminated union:
58
+ * `{ type: "actionOutput", schema }` for a single payload shape, or
59
+ * `{ type: "branchingOutput", branchSchemas }` for a per-branch map of shapes.
60
+ * Descriptive only — it is not enforced at runtime.
61
+ *
62
+ * @remarks
63
+ * Describes the `data` payload only, not the full return envelope
64
+ * (`statusCode`, `contentType`, state fields). `branchingOutput` requires
65
+ * `staticBranchNames`; it is not supported with `dynamicBranchInput`.
66
+ */
67
+ outputSchema?: OutputSchema;
40
68
  }
@@ -1,2 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PerformSafety = void 0;
4
+ /**
5
+ * Whether a perform is safe to invoke inline (to populate reference data in the Prismatic UI):
6
+ * `SAFE` to run as-is, `UNSAFE` if running has side effects, `NOT_ALLOWED` to opt out.
7
+ */
8
+ exports.PerformSafety = {
9
+ SAFE: "SAFE",
10
+ UNSAFE: "UNSAFE",
11
+ NOT_ALLOWED: "NOT_ALLOWED",
12
+ };
@@ -1,6 +1,8 @@
1
+ import type { PerformSafety } from "./ActionDefinition";
1
2
  import type { CollectionType } from "./ConfigVars";
2
3
  import type { DataSourceType } from "./DataSourceResult";
3
4
  import type { InputFieldType } from "./Inputs";
5
+ import type { OutputSchema } from "./OutputSchema";
4
6
  export interface ComponentManifest {
5
7
  key: string;
6
8
  public: boolean;
@@ -19,8 +21,13 @@ interface BaseInput {
19
21
  export interface ComponentManifestAction {
20
22
  key?: string;
21
23
  perform: (values: any) => Promise<unknown>;
24
+ examplePerform?: (values: any) => Promise<unknown>;
25
+ examplePerformSafety?: PerformSafety;
26
+ performSafety?: PerformSafety;
22
27
  inputs: Record<string, BaseInput>;
23
28
  examplePayload?: unknown;
29
+ /** Declares the shape of this action's output `data` as a JSON Schema (discriminated union: actionOutput | branchingOutput). */
30
+ outputSchema?: OutputSchema;
24
31
  }
25
32
  export interface ComponentManifestTrigger {
26
33
  key?: string;
@@ -0,0 +1,35 @@
1
+ import type { JsonSchema } from "./jsonforms/JsonSchema";
2
+ /**
3
+ * Describes the shape of a non-branching action's output `data` payload as a
4
+ * JSON Schema. Used by the Prismatic UI to let integration authors reference a
5
+ * step's output before a real execution has produced data. Descriptive only —
6
+ * it is not enforced at runtime.
7
+ */
8
+ export interface ActionOutputSchema {
9
+ type: "actionOutput";
10
+ schema: JsonSchema;
11
+ }
12
+ /**
13
+ * Describes the output `data` payload of a branching action, one JSON Schema
14
+ * per branch keyed by branch name. A branching action returns `{ branch, data }`,
15
+ * and the `data` shape may differ per branch, so each branch carries its own
16
+ * schema. Descriptive only — not enforced at runtime.
17
+ *
18
+ * @remarks
19
+ * Valid only for actions with `staticBranchNames` — a closed, build-time list.
20
+ * NOT supported with `dynamicBranchInput`, where branch names are computed at
21
+ * runtime and cannot be enumerated; publishing such a component is rejected
22
+ * server-side. (Unrelated to `dynamicObject` *inputs*, whose `configurations`
23
+ * are fully declared at build time — that's an input feature and does not
24
+ * affect `outputSchema`.)
25
+ */
26
+ export interface BranchingOutputSchema {
27
+ type: "branchingOutput";
28
+ branchSchemas: Record<string, JsonSchema>;
29
+ }
30
+ /**
31
+ * The output-schema contract declared on an action via `outputSchema`. A
32
+ * discriminated union on `type`: `actionOutput` for a single payload shape,
33
+ * `branchingOutput` for a per-branch map of payload shapes.
34
+ */
35
+ export type OutputSchema = ActionOutputSchema | BranchingOutputSchema;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -27,9 +27,9 @@ export * from "./Inputs";
27
27
  export * from "./InstanceAttributes";
28
28
  export * from "./IntegrationAttributes";
29
29
  export * from "./IntegrationDefinition";
30
+ export * from "./OutputSchema";
30
31
  export * from "./PollingTriggerDefinition";
31
32
  export * from "./ScopedConfigVars";
32
- export * from "./ScopedConfigVars";
33
33
  export * from "./TriggerDefinition";
34
34
  export * from "./TriggerEventFunction";
35
35
  export * from "./TriggerPayload";
@@ -43,9 +43,9 @@ __exportStar(require("./Inputs"), exports);
43
43
  __exportStar(require("./InstanceAttributes"), exports);
44
44
  __exportStar(require("./IntegrationAttributes"), exports);
45
45
  __exportStar(require("./IntegrationDefinition"), exports);
46
+ __exportStar(require("./OutputSchema"), exports);
46
47
  __exportStar(require("./PollingTriggerDefinition"), exports);
47
48
  __exportStar(require("./ScopedConfigVars"), exports);
48
- __exportStar(require("./ScopedConfigVars"), exports);
49
49
  __exportStar(require("./TriggerDefinition"), exports);
50
50
  __exportStar(require("./TriggerEventFunction"), exports);
51
51
  __exportStar(require("./TriggerPayload"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismatic-io/spectral",
3
- "version": "10.20.0",
3
+ "version": "10.21.1-preview.0",
4
4
  "description": "Utility library for building Prismatic connectors and code-native integrations",
5
5
  "keywords": [
6
6
  "prismatic"