integreat
Version:
Node.js integration layer
103 lines • 4.7 kB
JavaScript
import compareEndpoints from './utils/compareEndpoints.js';
import isEndpointMatch from './utils/isEndpointMatch.js';
import { populateActionAfterMutation } from '../utils/mutationHelpers.js';
import { ensureArray } from '../utils/array.js';
import { isNotNullOrUndefined, isObject } from '../utils/is.js';
import { combineResponses, setOrigin } from '../utils/response.js';
import prepareValidator from '../utils/validation.js';
const prepareMatch = ({ scope, ...match }) => scope === 'all' || !scope ? match : { scope, ...match };
const prepareEndpoint = ({ match, ...endpoint }) => ({
match: prepareMatch(match || {}),
...endpoint,
});
function runMutationAndPopulateAction(mutator) {
return () => async (action, state) => {
const mutatedAction = (await mutator(action, state));
return populateActionAfterMutation(action, mutatedAction);
};
}
const setModifyFlag = (def) => isObject(def) ? { ...def, $modify: true } : def;
const transformerFromAdapter = (serviceId, options = {}) => function createAdapterTransformer(adapter) {
const adapterId = adapter.id;
const preparedOptions = typeof adapterId === 'string'
? adapter.prepareOptions(options[adapterId] || {}, serviceId)
: {};
return () => async (action, state) => state.rev
? await adapter.serialize(action, preparedOptions)
: await adapter.normalize(action, preparedOptions);
};
function prepareActionMutation(serviceMutation, endpointMutation, serviceAdapterTransformer, endpointAdapterTransformer, mapTransform, mapOptions) {
const serviceMutator = mapTransform(ensureArray(serviceMutation)
.map(setModifyFlag)
.filter(isNotNullOrUndefined), mapOptions);
const endpointMutator = mapTransform(ensureArray(endpointMutation)
.map(setModifyFlag)
.filter(isNotNullOrUndefined), mapOptions);
const pipeline = [
...serviceAdapterTransformer.map((transformer) => ({
$transform: transformer,
})),
{ $transform: runMutationAndPopulateAction(serviceMutator) },
...endpointAdapterTransformer.map((transformer) => ({
$transform: transformer,
})),
{ $transform: runMutationAndPopulateAction(endpointMutator) },
];
return mapTransform(pipeline, mapOptions);
}
export default class Endpoint {
id;
match;
options;
allowRawRequest;
allowRawResponse;
castWithoutDefaults;
outgoingAuth;
incomingAuth;
#origin;
#validator;
#mutateAction;
#checkIfMatch;
constructor(endpointDef, serviceId, options, mapTransform, mapOptions, serviceMutation, serviceAdapters = [], endpointAdapters = [], outgoingAuth, incomingAuth) {
this.id = endpointDef.id;
this.#origin = endpointDef.id
? `service:${serviceId}:endpoint:${endpointDef.id}`
: `service:${serviceId}:endpoint`;
this.allowRawRequest = endpointDef.allowRawRequest;
this.allowRawResponse = endpointDef.allowRawResponse;
this.castWithoutDefaults = endpointDef.castWithoutDefaults ?? false;
this.match = endpointDef.match;
this.#checkIfMatch = isEndpointMatch(endpointDef, mapTransform, mapOptions);
this.options = options;
this.#validator = prepareValidator(endpointDef.validate, mapTransform, mapOptions);
this.#mutateAction = prepareActionMutation(serviceMutation, endpointDef.mutation || endpointDef.mutate, serviceAdapters.map(transformerFromAdapter(serviceId, options.adapters)), endpointAdapters.map(transformerFromAdapter(serviceId, options.adapters)), mapTransform, mapOptions);
this.outgoingAuth = outgoingAuth;
this.incomingAuth = incomingAuth;
}
async validateAction(action) {
const [errors] = await this.#validator(action);
const response = combineResponses(errors);
return response ? setOrigin(response, `validate:${this.#origin}`) : null;
}
async mutate(action, isRev) {
if (!action) {
throw new Error('Endpoint mutation was run without action');
}
return (await this.#mutateAction(action, { rev: isRev }));
}
async isMatch(action, isIncoming) {
return await this.#checkIfMatch(action, isIncoming);
}
static sortAndPrepare(endpointDefs) {
return endpointDefs.map(prepareEndpoint).sort(compareEndpoints);
}
static async findMatchingEndpoint(endpoints, action, isIncoming = false) {
for (const endpoint of endpoints) {
if (await endpoint.isMatch(action, isIncoming)) {
return endpoint;
}
}
return undefined;
}
}
//# sourceMappingURL=Endpoint.js.map