@prismatic-io/spectral
Version:
Utility library for building Prismatic connectors and code-native integrations
689 lines (688 loc) • 33.5 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertConfigVar = exports.convertInputValue = exports.convertFlow = exports.convertConfigPages = exports.convertIntegration = void 0;
const yaml_1 = __importDefault(require("yaml"));
const uuid_1 = require("uuid");
const assign_1 = __importDefault(require("lodash/assign"));
const camelCase_1 = __importDefault(require("lodash/camelCase"));
const pick_1 = __importDefault(require("lodash/pick"));
const types_1 = require("../types");
const convertComponent_1 = require("./convertComponent");
const integration_1 = require("./integration");
const merge_1 = __importDefault(require("lodash/merge"));
const context_1 = require("./context");
const path_1 = __importDefault(require("path"));
const fs_1 = require("fs");
const convertIntegration = (definition) => {
var _a, _b, _c;
// Generate a unique reference key that will be used to reference the
// actions, triggers, data sources, and connections that are created
// inline as part of the integration definition.
const referenceKey = (0, uuid_1.v4)();
const scopedConfigVars = (_a = definition.scopedConfigVars) !== null && _a !== void 0 ? _a : {};
const configVars = Object.values({
configPages: (_b = definition.configPages) !== null && _b !== void 0 ? _b : {},
userLevelConfigPages: (_c = definition.userLevelConfigPages) !== null && _c !== void 0 ? _c : {},
}).reduce((acc, configPages) => (Object.assign(Object.assign({}, acc), Object.values(configPages).reduce((acc, configPage) => Object.entries(configPage.elements).reduce((acc, [key, element]) => {
// "string" elements are HTML elements and should be ignored.
if (typeof element === "string") {
return acc;
}
if (key in acc || key in scopedConfigVars) {
throw new Error(`Duplicate config var key: "${key}"`);
}
return Object.assign(Object.assign({}, acc), { [key]: element });
}, acc), {}))), {});
let metadata = {};
try {
const metaDataPath = path_1.default.join("..", ".spectral", "metadata.json");
const file = (0, fs_1.readFileSync)(metaDataPath, { encoding: "utf-8" });
metadata = JSON.parse(file);
}
catch (e) {
// No-op. If there's no metadata file then we move on.
}
const cniComponent = codeNativeIntegrationComponent(definition, referenceKey, configVars);
const cniYaml = codeNativeIntegrationYaml(definition, referenceKey, configVars, metadata);
return Object.assign(Object.assign({}, cniComponent), { codeNativeIntegrationYAML: cniYaml });
};
exports.convertIntegration = convertIntegration;
const convertConfigPages = (pages, userLevelConfigured) => {
if (!pages || !Object.keys(pages).length) {
return [];
}
return Object.entries(pages).map(([name, { tagline, elements }]) => (Object.assign(Object.assign({ name,
tagline }, (userLevelConfigured ? { userLevelConfigured } : {})), { elements: Object.entries(elements)
.filter(([key, value]) => !(0, types_1.isConnectionScopedConfigVar)(value))
.map(([key, value]) => {
if (typeof value === "string") {
return {
type: "htmlElement",
value,
};
}
else if (value &&
typeof value === "object" &&
"dataType" in value &&
value.dataType === "htmlElement") {
return {
type: "htmlElement",
value: key,
};
}
return {
type: "configVar",
value: key,
};
}) })));
};
exports.convertConfigPages = convertConfigPages;
const codeNativeIntegrationYaml = ({ name, description, category, documentation, version, labels, endpointType, triggerPreprocessFlowConfig, flows, configPages, userLevelConfigPages, scopedConfigVars, instanceProfile = "Default Instance Profile", componentRegistry = {}, }, referenceKey, configVars, metadata) => {
// Find the preprocess flow config on the flow, if one exists.
const preprocessFlows = flows.filter((flow) => flow.preprocessFlowConfig);
// Do some validation of preprocess flow configs.
if (preprocessFlows.length > 1) {
throw new Error("Only one flow may define a Preprocess Flow Config.");
}
if (preprocessFlows.length && triggerPreprocessFlowConfig) {
throw new Error("Integration must not define both a Trigger Preprocess Flow Config and a Preprocess Flow.");
}
const hasPreprocessFlow = preprocessFlows.length > 0;
const preprocessFlowConfig = hasPreprocessFlow
? preprocessFlows[0].preprocessFlowConfig
: triggerPreprocessFlowConfig;
const nonPreprocessFlowTypes = ["instance_specific", "shared_instance"];
if (nonPreprocessFlowTypes.includes(endpointType || "flow_specific") && !preprocessFlowConfig) {
throw new Error("Integration with specified EndpointType must define either a Trigger Preprocess Flow Config or a Preprocess Flow.");
}
const configVarMap = Object.entries(scopedConfigVars !== null && scopedConfigVars !== void 0 ? scopedConfigVars : {}).reduce((acc, [key, value]) => {
if (typeof value === "string") {
return acc;
}
return Object.assign(Object.assign({}, acc), { [key]: value });
}, Object.assign({}, (configVars !== null && configVars !== void 0 ? configVars : {})));
const requiredConfigVars = [];
Object.entries(configVarMap).forEach(([key, configVar]) => {
if (!(0, types_1.isHtmlElementConfigVar)(configVar)) {
requiredConfigVars.push((0, exports.convertConfigVar)(key, configVar, referenceKey, componentRegistry));
}
});
// Transform the IntegrationDefinition into the structure that is appropriate
// for generating YAML, which will then be used by the Prismatic API to import
// the integration as a Code Native Integration.
const result = {
definitionVersion: integration_1.DefinitionVersion,
isCodeNative: true,
name,
description,
category,
documentation,
version,
labels,
requiredConfigVars,
endpointType,
preprocessFlowName: hasPreprocessFlow ? preprocessFlows[0].name : undefined,
externalCustomerIdField: fieldNameToReferenceInput(hasPreprocessFlow ? "onExecution" : "payload", preprocessFlowConfig === null || preprocessFlowConfig === void 0 ? void 0 : preprocessFlowConfig.externalCustomerIdField),
externalCustomerUserIdField: fieldNameToReferenceInput(hasPreprocessFlow ? "onExecution" : "payload", preprocessFlowConfig === null || preprocessFlowConfig === void 0 ? void 0 : preprocessFlowConfig.externalCustomerUserIdField),
flowNameField: fieldNameToReferenceInput(hasPreprocessFlow ? "onExecution" : "payload", preprocessFlowConfig === null || preprocessFlowConfig === void 0 ? void 0 : preprocessFlowConfig.flowNameField),
flows: flows.map((flow) => (0, exports.convertFlow)(flow, componentRegistry, referenceKey)),
defaultInstanceProfile: instanceProfile,
configPages: [
...(0, exports.convertConfigPages)(configPages, false),
...(0, exports.convertConfigPages)(userLevelConfigPages, true),
],
importMetadata: metadata,
};
return yaml_1.default.stringify(result);
};
const permissionAndVisibilityTypeValueMap = {
customer: {
orgOnly: false,
visibleToOrgDeployer: true,
visibleToCustomerDeployer: true,
},
embedded: {
orgOnly: false,
visibleToOrgDeployer: true,
visibleToCustomerDeployer: false,
},
organization: {
orgOnly: true,
visibleToOrgDeployer: true,
visibleToCustomerDeployer: false,
},
};
const getPermissionAndVisibilityValues = ({ permissionAndVisibilityType = "customer", visibleToOrgDeployer = true, }) => {
return Object.assign(Object.assign({}, permissionAndVisibilityTypeValueMap[permissionAndVisibilityType]), (visibleToOrgDeployer !== undefined ? { visibleToOrgDeployer } : {}));
};
/** Converts permission and visibility properties into `meta` properties for inputs. */
const convertInputPermissionAndVisibility = ({ permissionAndVisibilityType, visibleToOrgDeployer, }) => {
const meta = getPermissionAndVisibilityValues({
permissionAndVisibilityType,
visibleToOrgDeployer,
});
return meta;
};
/** Converts permission and visibility properties into `meta` properties for config vars. */
const convertConfigVarPermissionAndVisibility = ({ permissionAndVisibilityType, visibleToOrgDeployer: visibleToOrgDeployerBase, }) => {
const { orgOnly, visibleToCustomerDeployer, visibleToOrgDeployer } = getPermissionAndVisibilityValues({
permissionAndVisibilityType,
visibleToOrgDeployer: visibleToOrgDeployerBase,
});
return {
orgOnly,
meta: {
visibleToCustomerDeployer,
visibleToOrgDeployer,
},
};
};
const convertComponentReference = (componentReference, componentRegistry, referenceType) => {
var _a, _b;
const manifest = componentRegistry[componentReference.component];
if (!manifest) {
throw new Error(`Component with key "${componentReference.component}" not found in component registry.`);
}
const manifestEntry = manifest[referenceType][componentReference.key];
if (!manifestEntry) {
throw new Error(`Component with key "${componentReference.component}" does not have an entry with key "${componentReference.key}" in the component registry.`);
}
const ref = {
component: {
key: manifest.key,
signature: (_a = manifest.signature) !== null && _a !== void 0 ? _a : "",
isPublic: manifest.public,
},
// older versions of the manifest did not contain a key so we fall back to the componentReference key
key: (_b = manifestEntry.key) !== null && _b !== void 0 ? _b : componentReference.key,
};
const inputs = Object.entries(manifestEntry.inputs).reduce((result, [key, manifestEntryInput]) => {
var _a, _b, _c;
// Retrieve the input value or default to the manifest's default value
const value = (_b = (_a = componentReference.values) === null || _a === void 0 ? void 0 : _a[key]) !== null && _b !== void 0 ? _b : {
value: (_c = manifestEntryInput.default) !== null && _c !== void 0 ? _c : "",
};
const type = manifestEntryInput.collection
? "complex"
: "value" in value
? "value"
: "configVar";
if ("value" in value) {
const valueExpr = manifestEntryInput.collection === "keyvaluelist" && value.value instanceof Object
? Object.entries(value.value).map(([k, v]) => ({
name: { type: "value", value: k },
type: "value",
value: JSON.stringify(v),
}))
: manifestEntryInput.collection === "valuelist" && Array.isArray(value.value)
? value.value.map((v) => ({ type: "value", value: v }))
: value.value;
const formattedValue = type === "complex" || typeof valueExpr === "string"
? valueExpr
: JSON.stringify(valueExpr);
const meta = convertInputPermissionAndVisibility((0, pick_1.default)(value, ["permissionAndVisibilityType", "visibleToOrgDeployer"]));
const { writeOnly } = (0, pick_1.default)(value, ["writeOnly"]);
if (writeOnly) {
meta.writeOnly = writeOnly;
}
return Object.assign(Object.assign({}, result), { [key]: { type: type, value: formattedValue, meta } });
}
if ("configVar" in value) {
return Object.assign(Object.assign({}, result), { [key]: { type: "configVar", value: value.configVar } });
}
if ("template" in value) {
return Object.assign(Object.assign({}, result), { [key]: { type: "template", value: value.template } });
}
return result;
}, {});
return {
ref,
inputs,
};
};
const convertComponentRegistry = (componentRegistry, publicSupplementalComponent) => {
const convertedRegistry = Object.values(componentRegistry).map(({ key, public: isPublic, signature }) => ({
key,
signature: signature !== null && signature !== void 0 ? signature : "",
isPublic,
}));
if (publicSupplementalComponent) {
convertedRegistry.push({
key: `${publicSupplementalComponent}-triggers`,
isPublic: true,
version: "LATEST",
});
}
return convertedRegistry;
};
/**
* Create a reference to the private component built as part of this CNI.
*
* References to this component always use `version: "LATEST", isPublic: false`
* because they automatically publish alongside the corresponding CNI yml.
* */
const codeNativeIntegrationComponentReference = (referenceKey) => ({
key: referenceKey,
version: "LATEST",
isPublic: false,
});
/* A flow's trigger gets wrapped in a custom component if there's a defined
* onTrigger function, or if any custom onInstance behavior is defined.
* */
const flowUsesWrapperTrigger = (flow) => {
return typeof flow.onTrigger === "function" || flow.onInstanceDelete || flow.onInstanceDeploy;
};
const convertFlowSchemas = (flowKey, schemas) => {
return Object.entries(schemas).reduce((acc, [key, value]) => {
acc[key] = {
title: value.title || `${flowKey}-${key}`,
type: "object",
$comment: value.$comment,
properties: value.properties,
$schema: value.$schema || types_1.DEFAULT_JSON_SCHEMA_VERSION,
};
return acc;
}, {});
};
/** Converts a Flow into the structure necessary for YAML generation. */
const convertFlow = (flow, componentRegistry, referenceKey) => {
var _a;
const result = Object.assign({}, flow);
result.onTrigger = undefined;
result.trigger = undefined;
result.onInstanceDeploy = undefined;
result.onInstanceDelete = undefined;
result.onExecution = undefined;
result.preprocessFlowConfig = undefined;
result.errorConfig = undefined;
let publicSupplementalComponent;
const triggerStep = {
name: "On Trigger",
stableKey: `${flow.stableKey}-onTrigger`,
description: "The function that will be executed by the flow to return an HTTP response.",
isTrigger: true,
errorConfig: "errorConfig" in flow ? Object.assign({}, flow.errorConfig) : undefined,
};
const useWrapperTrigger = flowUsesWrapperTrigger(flow);
if ((0, types_1.isComponentReference)(flow.onTrigger) && !useWrapperTrigger) {
const { ref, inputs } = convertComponentReference(flow.onTrigger, componentRegistry, "triggers");
triggerStep.action = ref;
triggerStep.inputs = inputs;
}
else if (useWrapperTrigger) {
if (!flow.onTrigger) {
publicSupplementalComponent = flow.schedule ? "schedule" : "webhook";
}
triggerStep.action = {
key: flowFunctionKey(flow.name, "onTrigger"),
component: codeNativeIntegrationComponentReference(referenceKey),
};
}
else {
const hasSchedule = "schedule" in flow && typeof flow.schedule === "object";
const key = hasSchedule ? "schedule" : "webhook";
triggerStep.action = {
key,
component: {
key: `${key}-triggers`,
/**
* TODO: Add support for specific versions of platform triggers
*/
version: "LATEST",
isPublic: true,
},
};
}
if ("schedule" in flow && typeof flow.schedule === "object") {
const { schedule } = flow;
triggerStep.schedule = {
type: "configVar" in schedule ? "configVar" : "value",
value: "configVar" in schedule ? schedule.configVar : schedule.value,
meta: {
scheduleType: "custom",
timeZone: (_a = schedule.timezone) !== null && _a !== void 0 ? _a : "",
},
};
result.schedule = undefined;
}
const actionStep = {
action: {
key: flowFunctionKey(flow.name, "onExecution"),
component: codeNativeIntegrationComponentReference(referenceKey),
},
name: "On Execution",
stableKey: `${flow.stableKey}-onExecution`,
description: "The function that will be executed by the flow.",
errorConfig: "errorConfig" in flow ? Object.assign({}, flow.errorConfig) : undefined,
};
result.steps = [triggerStep, actionStep];
result.supplementalComponents = convertComponentRegistry(componentRegistry, publicSupplementalComponent);
result.schemas = flow.schemas ? convertFlowSchemas(flow.stableKey, flow.schemas) : undefined;
return result;
};
exports.convertFlow = convertFlow;
/** Converts an input value to the expected server type by its collection type. */
const convertInputValue = (value, collectionType) => {
if (collectionType !== "keyvaluelist") {
return value;
}
if (Array.isArray(value)) {
return value;
}
return Object.entries(value).map(([key, value]) => ({
key,
value: typeof value === "string" ? value : JSON.stringify(value),
}));
};
exports.convertInputValue = convertInputValue;
/** Converts a Config Var into the structure necessary for YAML generation. */
const convertConfigVar = (key, configVar, referenceKey, componentRegistry) => {
var _a, _b, _c;
if ((0, types_1.isConnectionScopedConfigVar)(configVar)) {
const { stableKey } = (0, pick_1.default)(configVar, ["stableKey"]);
return {
key,
stableKey,
dataType: "connection",
useScopedConfigVar: stableKey,
};
}
const { orgOnly, meta } = convertConfigVarPermissionAndVisibility((0, pick_1.default)(configVar, ["permissionAndVisibilityType", "visibleToOrgDeployer"]));
if ((0, types_1.isConnectionDefinitionConfigVar)(configVar)) {
const { stableKey, description } = (0, pick_1.default)(configVar, ["stableKey", "description"]);
return {
stableKey,
description,
key,
dataType: "connection",
connection: {
key: (0, camelCase_1.default)(key),
component: codeNativeIntegrationComponentReference(referenceKey),
},
inputs: Object.entries(configVar.inputs).reduce((result, [key, input]) => {
// Connection template inputs are never shown in the resulting YAML.
if (input.shown === false || "templateValue" in input) {
return result;
}
const meta = convertInputPermissionAndVisibility((0, pick_1.default)(input, ["permissionAndVisibilityType", "visibleToOrgDeployer"]));
if (input.writeOnly) {
meta.writeOnly = input.writeOnly;
}
const defaultValue = input.collection
? (input.default || []).map((defaultValue) => {
if (typeof defaultValue === "string") {
return {
type: "value",
value: defaultValue,
};
}
return {
name: defaultValue.key,
type: "value",
value: defaultValue.value,
};
})
: input.default || "";
return Object.assign(Object.assign({}, result), { [key]: {
type: input.collection ? "complex" : "value",
value: defaultValue,
meta,
} });
}, {}),
orgOnly,
meta: Object.assign(Object.assign({}, meta), ("oauth2Config" in configVar ? (_a = configVar.oauth2Config) !== null && _a !== void 0 ? _a : {} : {})),
};
}
if ((0, types_1.isConnectionReferenceConfigVar)(configVar)) {
const { ref, inputs } = convertComponentReference(configVar.connection, componentRegistry, "connections");
const { stableKey = "", description, connection: { template, onPremiseConnectionConfig }, } = (0, pick_1.default)(configVar, ["stableKey", "description", "connection"]);
return {
stableKey,
description,
key,
dataType: "connection",
onPremiseConnectionConfig,
connection: Object.assign(Object.assign({}, ref), { template }),
inputs,
orgOnly,
meta: Object.assign(Object.assign({}, meta), ("oauth2Config" in configVar ? (_b = configVar.oauth2Config) !== null && _b !== void 0 ? _b : {} : {})),
};
}
const rawDefaultValue = "defaultValue" in configVar
? (0, exports.convertInputValue)(configVar.defaultValue, configVar.collectionType)
: undefined;
const defaultValue = typeof rawDefaultValue !== "undefined"
? typeof rawDefaultValue === "string"
? rawDefaultValue
: JSON.stringify(rawDefaultValue)
: undefined;
const result = (0, assign_1.default)({ orgOnly, meta, key, defaultValue }, (0, pick_1.default)(configVar, [
"stableKey",
"description",
"dataType",
"pickList",
"timeZone",
"codeLanguage",
"collectionType",
]));
if ((0, types_1.isScheduleConfigVar)(configVar)) {
result.scheduleType = "custom";
}
if ((0, types_1.isJsonFormConfigVar)(configVar) || (0, types_1.isJsonFormDataSourceConfigVar)(configVar)) {
result.meta = Object.assign(Object.assign({}, result.meta), { validationMode: (_c = configVar === null || configVar === void 0 ? void 0 : configVar.validationMode) !== null && _c !== void 0 ? _c : "ValidateAndShow" });
}
if ((0, types_1.isDataSourceDefinitionConfigVar)(configVar)) {
result.dataType = configVar.dataSourceType;
result.dataSource = {
key: (0, camelCase_1.default)(key),
component: codeNativeIntegrationComponentReference(referenceKey),
};
}
if ((0, types_1.isDataSourceReferenceConfigVar)(configVar)) {
const { ref, inputs } = convertComponentReference(configVar.dataSource, componentRegistry, "dataSources");
result.dataType =
componentRegistry[configVar.dataSource.component].dataSources[ref.key].dataSourceType;
result.dataSource = ref;
result.inputs = inputs;
if (configVar.validationMode) {
result.meta = Object.assign(Object.assign({}, result.meta), { validationMode: configVar.validationMode });
}
}
return result;
};
exports.convertConfigVar = convertConfigVar;
/** Maps the step name field to a fully qualified input. */
const fieldNameToReferenceInput = (stepName, fieldName) => fieldName ? { type: "reference", value: `${stepName}.results.${fieldName}` } : undefined;
/** Actions and Triggers will be scoped to their flow by combining the flow
* name and the function name. This is to ensure that the keys are unique
* on the resulting object, which will be turned into a Component. */
const flowFunctionKey = (flowName, functionName) => {
const flowKey = flowName
.replace(/[^0-9a-zA-Z]+/g, " ")
.trim()
.split(" ")
.map((w, i) => i === 0 ? w.toLowerCase() : w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
.join("");
return `${flowKey}_${functionName}`;
};
/* Generates component argument for invokeTrigger calls. */
const invokeTriggerComponentInput = (componentRef, onTrigger, eventName) => {
const { component } = componentRef;
const inputComponent = "signature" in componentRef.component
? {
key: component.key,
signature: "signature" in component &&
component.signature !== null &&
component.signature !== void 0
? component.signature
: "",
isPublic: component.isPublic,
}
: component;
return {
component: inputComponent,
key: onTrigger ? onTrigger.key : componentRef.key,
triggerEventFunctionName: eventName,
};
};
/* Generates a wrapper function that calls an existing component trigger's perform. */
const generateTriggerPerformFn = (componentRef, onTrigger, componentRegistry) => {
const performFn = componentRef && typeof onTrigger !== "function"
? (context, payload, params) => __awaiter(void 0, void 0, void 0, function* () {
// @ts-expect-error: _components isn't part of the public API
const { _components } = context;
const invokeTrigger = _components.invokeTrigger;
const cniContext = (0, context_1.createCNIContext)(context, componentRegistry);
return yield invokeTrigger(invokeTriggerComponentInput(componentRef, onTrigger, "perform"), cniContext, payload, params);
})
: (context, payload, params) => __awaiter(void 0, void 0, void 0, function* () {
const cniContext = (0, context_1.createCNIContext)(context, componentRegistry);
return yield onTrigger(cniContext, payload, params);
});
return performFn;
};
/** Generates a wrapper function that calls an existing component's onInstanceDeploy
* or onInstanceDelete, then calls the flow-defined version if it exists.
* Returns the deep-merged results of the two, prioritizing the custom response
* if there's a conflict. */
const generateOnInstanceWrapperFn = (componentRef, onTrigger, eventName, componentRegistry, customFn) => {
const onInstanceFn = componentRef && typeof onTrigger !== "function"
? (context, params) => __awaiter(void 0, void 0, void 0, function* () {
// @ts-expect-error: _components isn't part of the public API
const { _components } = context;
const invokeTrigger = _components.invokeTrigger;
const cniContext = (0, context_1.createCNIContext)(context, componentRegistry);
const invokeResponse = (yield invokeTrigger(invokeTriggerComponentInput(componentRef, onTrigger, eventName), cniContext, null, params)) || {};
let customResponse = {};
if (customFn) {
customResponse = (yield customFn(cniContext, params)) || {};
}
return (0, merge_1.default)(invokeResponse, customResponse);
})
: (context, params) => __awaiter(void 0, void 0, void 0, function* () {
if (customFn) {
const cniContext = (0, context_1.createCNIContext)(context, componentRegistry);
return yield customFn(cniContext, params);
}
});
return onInstanceFn;
};
const convertOnExecution = (onExecution, componentRegistry) => (context, params) => __awaiter(void 0, void 0, void 0, function* () {
const actionContext = (0, context_1.createCNIContext)(context, componentRegistry);
const result = yield onExecution(actionContext, params);
(0, context_1.logDebugResults)(actionContext);
return result;
});
/** Creates the structure necessary to import a Component as part of a
* Code Native integration. */
const codeNativeIntegrationComponent = ({ name, iconPath, description, flows = [], componentRegistry = {} }, referenceKey, configVars) => {
const convertedActions = flows.reduce((result, { name, onExecution }) => {
const key = flowFunctionKey(name, "onExecution");
return Object.assign(Object.assign({}, result), { [key]: {
key,
display: {
label: `${name} - onExecution`,
description: "The function that will be executed by the flow.",
},
perform: convertOnExecution(onExecution, componentRegistry),
inputs: [],
} });
}, {});
const convertedTriggers = flows.reduce((result, { name, onTrigger, onInstanceDeploy, onInstanceDelete, schedule }) => {
if (!flowUsesWrapperTrigger({
onTrigger,
onInstanceDelete,
onInstanceDeploy,
})) {
// In this scenario, the user has defined an existing component trigger
// without any custom behavior, so we don't need to wrap anything.
return result;
}
const key = flowFunctionKey(name, "onTrigger");
const defaultComponentKey = schedule && typeof schedule === "object" ? "schedule" : "webhook";
const defaultComponentRef = {
component: {
key: `${defaultComponentKey}-triggers`,
version: "LATEST",
isPublic: true,
},
key: defaultComponentKey,
};
// The component ref here is undefined if onTrigger is a function.
const { ref } = (0, types_1.isComponentReference)(onTrigger)
? convertComponentReference(onTrigger, componentRegistry, "triggers")
: { ref: onTrigger ? undefined : defaultComponentRef };
const performFn = generateTriggerPerformFn(ref, onTrigger, componentRegistry);
const deleteFn = generateOnInstanceWrapperFn(ref, onTrigger, "onInstanceDelete", componentRegistry, onInstanceDelete);
const deployFn = generateOnInstanceWrapperFn(ref, onTrigger, "onInstanceDeploy", componentRegistry, onInstanceDeploy);
return Object.assign(Object.assign({}, result), { [key]: {
key,
display: {
label: `${name} - onTrigger`,
description: "The function that will be executed by the flow to return an HTTP response.",
},
perform: performFn,
onInstanceDeploy: deployFn,
hasOnInstanceDeploy: !!deployFn,
onInstanceDelete: deleteFn,
hasOnInstanceDelete: !!deleteFn,
inputs: [],
scheduleSupport: "valid",
synchronousResponseSupport: "valid",
} });
}, {});
const convertedDataSources = Object.entries(configVars).reduce((result, [key, configVar]) => {
if (!(0, types_1.isDataSourceDefinitionConfigVar)(configVar)) {
return result;
}
const camelKey = (0, camelCase_1.default)(key);
const dataSource = (0, pick_1.default)(configVar, ["perform", "dataSourceType"]);
return Object.assign(Object.assign({}, result), { [camelKey]: Object.assign(Object.assign({}, dataSource), { key: camelKey, display: {
label: key,
description: key,
}, inputs: [] }) });
}, {});
const convertedConnections = Object.entries(configVars).reduce((result, [key, configVar]) => {
var _a;
if (!(0, types_1.isConnectionDefinitionConfigVar)(configVar)) {
return result;
}
const convertedInputs = Object.entries(configVar.inputs).map(([key, value]) => {
if ("templateValue" in value) {
return (0, convertComponent_1.convertTemplateInput)(key, value, configVar.inputs);
}
return (0, convertComponent_1.convertInput)(key, value);
});
const connection = (0, pick_1.default)(configVar, ["oauth2Type", "oauth2PkceMethod"]);
const { avatarPath: avatarIconPath, oauth2ConnectionIconPath: iconPath } = (_a = configVar.icons) !== null && _a !== void 0 ? _a : {};
return [
...result,
Object.assign(Object.assign({}, connection), { iconPath,
avatarIconPath, inputs: convertedInputs, key: (0, camelCase_1.default)(key), label: key }),
];
}, []);
return {
key: referenceKey,
display: {
label: referenceKey,
iconPath,
description: description || name,
},
connections: convertedConnections,
actions: convertedActions,
triggers: convertedTriggers,
dataSources: convertedDataSources,
};
};