integreat
Version:
Node.js integration layer
142 lines • 5.94 kB
JavaScript
import EventEmitter from 'node:events';
import defaultMapTransform from 'map-transform';
import Auth from './service/Auth.js';
import builtinHandlers from './handlers/index.js';
import runFn from './handlers/run.js';
import Schema from './schema/Schema.js';
import Service from './service/Service.js';
import { ensureArray } from './utils/array.js';
import createMapOptions from './utils/createMapOptions.js';
import { lookupById } from './utils/indexUtils.js';
import createDispatch from './dispatch.js';
import listen from './listen.js';
import stopListening from './stopListening.js';
import close from './close.js';
import { indexById } from './utils/indexUtils.js';
import Job from './jobs/Job.js';
import createDispatchScheduled from './dispatchScheduled.js';
export const setUpAuth = (authenticators) => function setUpAuth(def) {
const authenticator = lookupById(def.authenticator, authenticators);
if (!authenticator) {
throw new Error(`Auth config '${def.id}' references an unknown authenticator id '${def.authenticator}'`);
}
return new Auth(def.id, authenticator, def.options, def.overrideAuthAsMethod);
};
const setAdapterIds = (adapters) => adapters
? Object.fromEntries(Object.entries(adapters).map(([id, adapter]) => [
id,
{ ...adapter, id },
]))
: {};
const isJobWithSchedule = (job) => !!job.schedule;
function prepareSchemas(schemaDefs) {
const schemas = new Map();
schemaDefs.forEach((def) => {
schemas.set(def.id, new Schema(def, schemas));
});
return schemas;
}
const setIdOnAuthenticators = (authenticators) => Object.fromEntries(Object.entries(authenticators ?? {}).map(([id, auth]) => [
id,
{ ...auth, id },
]));
const createAuthObjects = (authDefs, authenticators) => authDefs
.map(setUpAuth(authenticators))
.reduce(indexById, {});
function prepareJobs(jobDefs, mapTransform, mapOptions, failOnErrorInPostconditions) {
const jobs = new Map();
ensureArray(jobDefs).forEach((jobDef) => {
const job = new Job(jobDef, mapTransform, mapOptions, failOnErrorInPostconditions);
jobs.set(job.id, job);
});
return jobs;
}
const combineHandlers = (handlers, jobs) => ({
...builtinHandlers,
...handlers,
RUN: runFn(jobs),
});
const handlerOptionsFromDefs = (defs) => ({
identConfig: defs.identConfig,
queueService: defs.queueService,
});
const hasService = (services, id) => services.some((service) => service.id === id);
function createServices(defs, resources, schemas, mapTransform, mapOptions, middlewareForService, emit) {
const authenticators = setIdOnAuthenticators(resources.authenticators || {});
const auths = createAuthObjects(defs.auths || [], authenticators);
return defs.services
.map((def) => new Service(def, {
transporters: resources.transporters,
adapters: setAdapterIds(resources.adapters),
authenticators: authenticators,
auths,
schemas,
mapTransform,
mapOptions,
middleware: middlewareForService,
emit,
}))
.reduce(indexById, {});
}
function setupServicesAndDispatch(defs, resources, schemas, middlewareForDispatch, middlewareForService, emit, dispatchedActionId) {
const mapTransformFn = resources.mapTransform ?? defaultMapTransform;
const mapOptions = createMapOptions(schemas, defs.mutations, resources.transformers, defs.dictionaries, defs.nonvalues);
const services = createServices(defs, resources, schemas, mapTransformFn, mapOptions, middlewareForService, emit);
const failOnErrorInPostconditions = defs.flags?.failOnErrorInPostconditions ??
defs.flags?.breakByDefault ??
false;
const jobs = prepareJobs(defs.jobs || [], mapTransformFn, mapOptions, failOnErrorInPostconditions);
const dispatch = createDispatch({
schemas,
services,
handlers: combineHandlers(resources.handlers || {}, jobs),
middleware: middlewareForDispatch,
options: handlerOptionsFromDefs(defs),
actionIds: dispatchedActionId,
emit,
});
const dispatchScheduled = createDispatchScheduled(dispatch, [...jobs.values()].filter(isJobWithSchedule));
return { services, dispatch, dispatchScheduled };
}
export default class Instance extends EventEmitter {
id;
services;
schemas;
identType;
queueService;
dispatch;
dispatchScheduled;
#dispatchedActionId;
constructor(defs, resources, middlewareForDispatch = [], middlewareForService = []) {
super();
if (!Array.isArray(defs.services) || !Array.isArray(defs.schemas)) {
throw new TypeError('Please provide at least one service and one schema');
}
else if (typeof defs.queueService === 'string' &&
!hasService(defs.services, defs.queueService)) {
throw new TypeError(`Please make sure the provided queue service id '${defs.queueService}' is among the services in your setup`);
}
this.id = defs.id;
this.identType = defs.identConfig?.type;
this.queueService = defs.queueService;
this.schemas = prepareSchemas(defs.schemas);
this.#dispatchedActionId = new Set();
const { services, dispatch, dispatchScheduled } = setupServicesAndDispatch(defs, resources, this.schemas, middlewareForDispatch, middlewareForService, this.emit.bind(this), this.#dispatchedActionId);
this.services = services;
this.dispatch = dispatch;
this.dispatchScheduled = dispatchScheduled;
}
get dispatchedCount() {
return this.#dispatchedActionId.size;
}
async listen() {
return listen(Object.values(this.services), this.dispatch);
}
async stopListening() {
return stopListening(Object.values(this.services));
}
async close() {
return close(Object.values(this.services));
}
}
//# sourceMappingURL=Instance.js.map