entangle.ts
Version:
A declarative, event-driven framework for orchestrating business logic in TypeScript & Node.js applications.
310 lines (309 loc) • 14 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Superposition = void 0;
const HawkingRadiation_1 = require("../hawking-radiation/HawkingRadiation");
const ConsoleLogger_1 = require("../logging/ConsoleLogger");
const Logging_1 = require("../logging/Logging");
const QuantumPointer_1 = require("../quantum-pointer/QuantumPointer");
const Notation_1 = require("../shared/Notation");
const Logging_types_1 = require("../shared/types/Logging.types");
const Gateway_builder_1 = require("./builders/Gateway.builder");
/**
* In quantum mechanics, Superposition is the principle that a system can exist in
* multiple potential states at once, collapsing into a single reality upon observation.
*
* In Entangle.ts, the `Superposition` class is the embodiment of this principle.
* It is the central orchestrator—the "laws of physics" for your application.
* It listens for events from the Aether, consults the EventHorizon for historical
* context, and executes rule-based interactions, creating and manipulating
* particles within the HiggsField and its temporary scopes.
*
* @class Superposition
* @param aether The communication medium, responsible for event transport.
* @param higgs The foundational field, the main container for service particles.
* @param horizon The historical record, providing context of all past events.
*/
class Superposition {
constructor(aether, higgs, horizon, errorHandler) {
this.aether = aether;
this.higgs = higgs;
this.horizon = horizon;
this.errorHandler = errorHandler;
this.particlesContracts = new Map();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.contracts = [];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.interactions = [];
this.logger = new Logging_1.Logging('custom', new ConsoleLogger_1.ConsoleLogger());
}
/**
* Begins the declarative definition of a rule that is triggered by a specific event.
* This is the entry point for defining any "law" in the application.
* @param event The name of the event that triggers the rule.
* @returns A `GatewayBuilder` instance to continue defining the rule by choosing an
* action (`.build()` or `.use()`).
*/
upon(event) {
return new Gateway_builder_1.GatewayBuilder(this, event);
}
/**
* Check if there are any particles that can be created
*/
checkForParticlesCreation(event, entanglement) {
const filteredContracts = this.contracts.filter((contract) => contract.upon === event && contract.entanglement === entanglement);
for (const contract of filteredContracts) {
const shouldCreateAParticle = this.canCreateAParticle(contract);
if (shouldCreateAParticle) {
this.createAParticle(contract);
}
}
}
/**
* Checks if a particle creation rule can be executed based on its `when` clause.
* @internal
*/
canCreateAParticle(contract) {
const { upon, when, is, requirements } = contract;
// Checks if the 'when' clause is satisfied
if (typeof when !== 'undefined') {
const notation = Notation_1.Notation.create(when);
const data = this.horizon.query().from(upon).using(notation).get();
const parsedData = notation.getData(data);
if (parsedData !== is) {
this.logger.log({
type: Logging_types_1.ELogType.CREATION,
message: `Condition not met for particle creation: expected '${is}', got '${parsedData}'`,
});
return false;
}
}
// Checks if the requirements are satisfied.
// If not, nothing happens
if (requirements === null || requirements === void 0 ? void 0 : requirements.length) {
for (const event of requirements) {
const eventOcurred = this.horizon.query().from(event).using(Notation_1.Notation.create()).get();
if (eventOcurred === undefined) {
this.logger.log({
type: Logging_types_1.ELogType.CREATION,
message: `Requirement not met for particle creation: event '${event}' has not occurred`,
});
return false;
}
}
}
return true;
}
/**
* Creates a particle instance and registers it within the specified scope
* (or the main HiggsField if no scope is provided), making it available for
* other interactions.
* @internal
*/
createAParticle(contract) {
const { upon, build, using, then, scope, emit, lifecycle, destroyOnInteraction, errorHandler, entanglement, } = contract;
const context = scope !== null && scope !== void 0 ? scope : this.higgs;
const selectedErrorhandler = errorHandler !== null && errorHandler !== void 0 ? errorHandler : this.errorHandler;
const parsedArgs = using
? using.map((arg) => {
if (arg instanceof Notation_1.Notation) {
return arg.getData(this.horizon.query().from(upon).get());
}
if (arg instanceof QuantumPointer_1.QuantumPointer) {
return arg.get();
}
if (arg instanceof HawkingRadiation_1.HawkingRadiation) {
return arg.get();
}
return arg;
})
: [];
try {
this.logger.log({
type: Logging_types_1.ELogType.CREATION,
message: `Creating particle ${build.name} with arguments [${parsedArgs.join(',')}]`,
});
context.register(build, () => new build(...parsedArgs), {
destroyOnInteraction,
lifecycle,
});
const particle = new build(...parsedArgs);
this.logger.log({
message: `Particle ${build.name} were built with arguments [${parsedArgs.join(',')}]`,
type: Logging_types_1.ELogType.CREATION,
});
if (then) {
this.logger.log({
message: `Executing 'then' callback for particle ${build.name}`,
type: Logging_types_1.ELogType.INTERACTION,
});
Promise.resolve(particle).then((res) => then(res));
}
if (emit) {
this.logger.log({
message: `Emitting event '${emit}' with entanglement '${entanglement}' for particle ${build.name}`,
type: Logging_types_1.ELogType.INTERACTION,
});
this.aether.emit(emit, entanglement, particle);
}
}
catch (err) {
selectedErrorhandler === null || selectedErrorhandler === void 0 ? void 0 : selectedErrorhandler.handle(err, {
rule: contract,
event: upon,
eventArgs: parsedArgs,
});
}
}
/**
* Registers a particle creation contract, setting up a listener for its trigger event.
* This method is intended to be called by a builder.
* @internal
*/
addContract(contract) {
const { upon, once } = contract;
const subscribeMethod = once ? 'once' : 'on';
this.aether[subscribeMethod](upon, (boson) => {
const { payload, entanglement } = boson;
this.logger.log({
type: Logging_types_1.ELogType.CREATION,
message: `Event '${upon}' entangled to '${entanglement}' received payload: ${JSON.stringify(payload)}`,
});
this.horizon.add(upon, payload);
this.checkForParticlesCreation(upon, entanglement);
this.checkForParticlesInteractions(upon, entanglement);
});
this.contracts.push(contract);
return this;
}
/**
* Registers an interaction contract, setting up a listener if it's event-driven.
* This method is intended to be called by a builder.
* @internal
*/
addInteraction(interaction) {
this.interactions.push(interaction);
const { upon, once } = interaction;
const subscribeMethod = once ? 'once' : 'on';
if (upon) {
this.aether[subscribeMethod](upon, (boson) => {
const { payload, entanglement } = boson;
this.logger.log({
type: Logging_types_1.ELogType.INTERACTION,
message: `Event '${upon}' entangled to '${entanglement}' received payload: ${JSON.stringify(payload)}`,
});
this.horizon.add(upon, payload);
this.checkForParticlesCreation(upon, entanglement);
this.checkForParticlesInteractions(upon, entanglement);
});
}
return this;
}
/**
* Checks for and executes all interaction rules triggered by a specific event.
* @internal
*/
checkForParticlesInteractions(event, entanglement) {
const filteredInteractions = this.interactions.filter((i) => i.upon === event && i.entanglement === entanglement);
for (const interaction of filteredInteractions) {
const { use: target } = interaction;
let instance;
if (target instanceof Notation_1.Notation) {
instance = this.horizon.query().using(target).get();
}
else if (target instanceof QuantumPointer_1.QuantumPointer) {
instance = target.get();
}
else {
instance = this.higgs.get(target);
}
if (!instance) {
this.logger.log({
type: Logging_types_1.ELogType.ERROR,
message: `Could not resolve instance for target: ${JSON.stringify(target)}`,
});
throw new Error('Instance could not be resolved from target.');
}
this.interact(interaction, instance);
}
}
interact(interaction, instance) {
var _a;
const { use: target, call, with: args, then, emit, errorHandler, upon, entanglement, } = interaction;
const selectedErrorhandler = errorHandler !== null && errorHandler !== void 0 ? errorHandler : this.errorHandler;
try {
const _args = [];
if (args) {
for (const arg of args) {
if (arg instanceof Notation_1.Notation) {
_args.push(arg.getData(this.horizon.query().get()));
continue;
}
if (arg instanceof HawkingRadiation_1.HawkingRadiation) {
_args.push(arg.get());
}
_args.push(arg);
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const methodToCall = instance[call];
if (typeof methodToCall === 'function') {
this.logger.log({
type: Logging_types_1.ELogType.INTERACTION,
message: `Executing method '${String(call)}' on particle ${instance.constructor.name} with arguments [${_args.join(',')}]`,
});
const result = Promise.resolve(methodToCall.bind(instance)(..._args));
this.logger.log({
message: `Executed method '${String(call)}' on particle ${instance.constructor.name} with arguments [${_args.join(',')}]`,
type: Logging_types_1.ELogType.INTERACTION,
});
result
.then((res) => {
if (then) {
this.logger.log({
message: `Executing 'then' callback for particle ${instance.constructor.name}`,
type: Logging_types_1.ELogType.INTERACTION,
});
then(res);
}
})
.catch((err) => {
selectedErrorhandler === null || selectedErrorhandler === void 0 ? void 0 : selectedErrorhandler.handle(err, {
rule: interaction,
event: upon,
eventArgs: _args,
});
});
if (emit) {
this.logger.log({
message: `Emitting event '${emit}' with entanglement '${entanglement}' for particle ${instance.constructor.name}`,
type: Logging_types_1.ELogType.INTERACTION,
});
this.aether.emit(emit, entanglement, result);
}
}
else {
const errDesc = `Method "${String(call)}" does not exist or is not a function on particle "${instance.constructor.name}".`;
this.logger.log({
type: Logging_types_1.ELogType.ERROR,
message: errDesc,
});
throw new Error(errDesc);
}
if (!((_a = this.higgs.getParticleOptions(target)) === null || _a === void 0 ? void 0 : _a.destroyOnInteraction)) {
this.higgs.destroy(target);
this.logger.log({
message: `Particle ${instance.constructor.name} destroyed`,
type: Logging_types_1.ELogType.DESTRUCTION,
});
}
}
catch (err) {
selectedErrorhandler === null || selectedErrorhandler === void 0 ? void 0 : selectedErrorhandler.handle(err, {
rule: interaction,
event: upon,
eventArgs: args,
});
}
}
}
exports.Superposition = Superposition;