@prismatic-io/spectral
Version:
Utility library for building Prismatic connectors and code-native integrations
136 lines (135 loc) • 7.38 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.createInvokeFlow = void 0;
exports.createCNIContext = createCNIContext;
exports.createDebugContext = createDebugContext;
exports.logDebugResults = logDebugResults;
const node_perf_hooks_1 = require("node:perf_hooks");
const node_process_1 = require("node:process");
const axios_1 = __importDefault(require("axios"));
const convertIntegration_1 = require("./convertIntegration");
const MEMORY_USAGE_CONVERSION = 1024 * 1024;
function createCNIContext(context, componentRegistry) {
// Component, debug, and invokeFlow methods are not provided as part of the server context.
// They are added to the context via spectral, here.
var _a;
// @ts-expect-error _components isn't part of the public API
const _components = (_a = context._components) !== null && _a !== void 0 ? _a : { invoke: () => { } };
const invoke = _components.invoke;
// Construct the component methods from the component registry
const componentMethods = Object.entries(componentRegistry).reduce((accumulator, [registryComponentKey, { key: componentKey, actions, public: isPublic, signature }]) => {
const componentActions = Object.entries(actions).reduce((actionsAccumulator, [registryActionKey, action]) => {
const manifestActions = componentRegistry[registryComponentKey].actions[registryActionKey];
// Define the method to be called for the action
const invokeAction = (values) => __awaiter(this, void 0, void 0, function* () {
var _a;
// Apply defaults directly within the transformation process
const transformedValues = Object.entries(manifestActions.inputs).reduce((transformedAccumulator, [inputKey, inputValueBase]) => {
var _a;
const inputValue = (_a = values[inputKey]) !== null && _a !== void 0 ? _a : inputValueBase.default;
const { collection } = inputValueBase;
return Object.assign(Object.assign({}, transformedAccumulator), { [inputKey]: (0, convertIntegration_1.convertInputValue)(inputValue, collection) });
}, {});
// Invoke the action with the transformed values
return invoke({
component: {
key: componentKey,
signature: signature !== null && signature !== void 0 ? signature : "",
isPublic,
},
// older versions of manifests did not contain action.key so we fall back to the registry key
key: (_a = action.key) !== null && _a !== void 0 ? _a : registryActionKey,
}, Object.assign(Object.assign({}, context), { debug: createDebugContext(context) }), transformedValues);
});
return Object.assign(Object.assign({}, actionsAccumulator), { [registryActionKey]: invokeAction });
}, {});
return Object.assign(Object.assign({}, accumulator), { [registryComponentKey]: componentActions });
}, {});
return Object.assign(Object.assign({}, context), { debug: createDebugContext(context), components: componentMethods, invokeFlow: (0, exports.createInvokeFlow)(context, { isCNI: true }) });
}
function createDebugContext(context) {
const globalDebug = Boolean(context.globalDebug);
return {
enabled: globalDebug,
timeElapsed: {
mark: (actionContext, label) => {
if (globalDebug) {
actionContext.debug.results.timeElapsed.marks[label] = node_perf_hooks_1.performance.now();
}
},
measure: (actionContext, label, marks) => {
if (globalDebug) {
actionContext.debug.results.timeElapsed.measurements[label] = {
marks,
duration: actionContext.debug.results.timeElapsed.marks[marks.end] -
actionContext.debug.results.timeElapsed.marks[marks.start],
};
}
},
},
memoryUsage: (actionContext, label, showDetail) => {
if (globalDebug) {
const usage = showDetail ? memoryUsageInMB() : node_process_1.memoryUsage.rss() / MEMORY_USAGE_CONVERSION;
actionContext.debug.results.memoryUsage.push({
mark: label,
rss: typeof usage === "number" ? usage : usage.rss,
detail: typeof usage === "number" ? undefined : usage,
});
}
},
results: {
timeElapsed: { marks: {}, measurements: {} },
memoryUsage: [],
allowedMemory: Number(context.runnerAllocatedMemoryMb),
},
};
}
function logDebugResults(context) {
if (context.debug.enabled) {
context.logger.metric(context.debug.results);
}
}
function memoryUsageInMB() {
const usage = (0, node_process_1.memoryUsage)();
return Object.keys(usage).reduce((accum, key) => {
accum[key] = usage[key] / MEMORY_USAGE_CONVERSION;
return accum;
}, {
rss: -1,
heapTotal: -1,
heapUsed: -1,
external: -1,
arrayBuffers: -1,
});
}
function formatExecutionFrameHeaders(frame, source) {
let frameToUse = frame;
if (source) {
frameToUse = Object.assign(Object.assign({}, frame), { customSource: source });
}
return JSON.stringify(frameToUse);
}
const createInvokeFlow = (context, options = {}) => {
return (flowName, data, config, source) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
const sourceToUse = options.isCNI ? source : undefined;
return yield axios_1.default.post(context.webhookUrls[flowName], data, Object.assign(Object.assign({}, config), { headers: Object.assign(Object.assign(Object.assign({}, ((_a = config === null || config === void 0 ? void 0 : config.headers) !== null && _a !== void 0 ? _a : {})), (((_b = context.webhookApiKeys[flowName]) === null || _b === void 0 ? void 0 : _b.length) > 0
? {
"Api-Key": context.webhookApiKeys[flowName][0],
}
: {})), { "prismatic-invoked-by": formatExecutionFrameHeaders(context.executionFrame, sourceToUse), "prismatic-invoke-type": "Cross Flow", "prismatic-executionid": context.executionId }) }));
});
};
exports.createInvokeFlow = createInvokeFlow;