senecajs/seneca

View on GitHub
lib/inward.js

Summary

Maintainability
B
6 hrs
Test Coverage
"use strict";
/* Copyright © 2010-2023 Richard Rodger and other contributors, MIT License. */
Object.defineProperty(exports, "__esModule", { value: true });
exports.Inward = void 0;
const common_1 = require("./common");
const intern = {};
function inward_msg_modify(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var meta = data.meta;
    if (ctx.actdef) {
        var fixed = ctx.actdef.fixed;
        var custom = ctx.actdef.custom;
        if (fixed) {
            Object.assign(data.msg, fixed);
        }
        if (custom) {
            meta.custom = meta.custom || {};
            Object.assign(meta.custom, custom);
        }
    }
}
function inward_limit_msg(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var so = ctx.options;
    var meta = data.meta;
    if (meta.parents && so.limits.maxparents < meta.parents.length) {
        return {
            op: 'stop',
            out: {
                kind: 'error',
                code: 'maxparents',
                info: {
                    maxparents: so.limits.maxparents,
                    numparents: meta.parents.length,
                    parents: meta.parents.map((p) => p[common_1.TRACE_PATTERN] + ' ' + p[common_1.TRACE_ACTION]),
                    args: (0, common_1.inspect)((0, common_1.clean)(data.msg)).replace(/\n/g, ''),
                },
            },
        };
    }
}
function inward_announce(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    if (!ctx.actdef)
        return;
    // Only intended for use in a per-delegate context.
    if ('function' === typeof ctx.seneca.on_act_in) {
        ctx.seneca.on_act_in(ctx.actdef, data.msg, data.meta);
    }
    ctx.seneca.emit('act-in', data.msg, null, data.meta);
}
// TODO: allow if not a top level call - close gracefully
function inward_closed(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    if (ctx.seneca.flags.closed && !data.meta.closing) {
        return {
            op: 'stop',
            out: {
                kind: 'error',
                code: 'closed',
                info: {
                    args: (0, common_1.inspect)((0, common_1.clean)(data.msg)).replace(/\n/g, ''),
                },
            },
        };
    }
}
function inward_act_stats(spec) {
    const ctx = spec.ctx;
    if (!ctx.actdef) {
        return;
    }
    var private$ = ctx.seneca.private$;
    ++private$.stats.act.calls;
    var pattern = ctx.actdef.pattern;
    var actstats = (private$.stats.actmap[pattern] =
        private$.stats.actmap[pattern] || {});
    ++actstats.calls;
}
function inward_act_default(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var so = ctx.options;
    var msg = data.msg;
    var meta = data.meta;
    // TODO: existence of pattern action needs own indicator flag
    if (!ctx.actdef) {
        var default$ = meta.dflt || (!so.strict.find ? {} : meta.dflt);
        if (null != default$ &&
            ('object' === typeof default$ || Array.isArray(default$))) {
            return {
                op: 'stop',
                out: {
                    kind: 'result',
                    result: default$,
                    log: {
                        level: 'debug',
                        data: {
                            kind: 'act',
                            case: 'DEFAULT',
                        },
                    },
                },
            };
        }
        else if (null != default$) {
            return {
                op: 'stop',
                out: {
                    kind: 'error',
                    code: 'act_default_bad',
                    info: {
                        args: (0, common_1.inspect)((0, common_1.clean)(msg)).replace(/\n/g, ''),
                        xdefault: (0, common_1.inspect)(default$),
                    },
                },
            };
        }
    }
}
function inward_act_not_found(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var so = ctx.options;
    var msg = data.msg;
    // console.log('NO ACTDEF', ctx.actdef, msg, data)
    if (!ctx.actdef) {
        return {
            op: 'stop',
            out: {
                kind: 'error',
                code: 'act_not_found',
                info: { args: (0, common_1.inspect)((0, common_1.clean)(msg)).replace(/\n/g, '') },
                log: {
                    level: so.trace.unknown ? 'warn' : 'debug',
                    data: {
                        kind: 'act',
                        case: 'UNKNOWN',
                    },
                },
            },
        };
    }
}
function inward_validate_msg(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var so = ctx.options;
    var msg = data.msg;
    var err = null;
    if (so.valid.active && so.valid.message) {
        if (ctx.actdef.gubu) {
            // TODO: gubu option to provide Error without throwing
            // TODO: how to expose gubu builders, Required, etc?
            // TODO: use original msg for error
            try {
                data.msg = ctx.actdef.gubu(msg);
            }
            catch (e) {
                err = e;
            }
        }
        else if ('function' === typeof ctx.actdef.validate) {
            // FIX: this is assumed to be synchronous
            // seneca-parambulator and seneca-joi need to be updated
            ctx.actdef.validate(msg, function (verr) {
                err = verr;
            });
        }
    }
    if (err) {
        return {
            op: 'stop',
            out: {
                kind: 'error',
                code: so.legacy.error_codes ? 'act_invalid_args' : 'act_invalid_msg',
                info: {
                    pattern: ctx.actdef.pattern,
                    message: err.message,
                    msg: (0, common_1.clean)(msg),
                    error: err,
                    props: err.gubu ? err.props : [],
                },
                log: {
                    level: so.trace.invalid ? 'warn' : null,
                    data: {
                        kind: 'act',
                        case: 'INVALID',
                    },
                },
            },
        };
    }
}
// Check if actid has already been seen, and if action cache is active,
// then provide cached result, if any. Return true in this case.
function inward_act_cache(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var so = ctx.options;
    var meta = data.meta;
    var actid = meta.id;
    var private$ = ctx.seneca.private$;
    if (actid != null && so.history.active) {
        var actdetails = private$.history.get(actid);
        if (actdetails) {
            private$.stats.act.cache++;
            var latest = actdetails.result[actdetails.result.length - 1] || {};
            var out = {
                op: 'stop',
                out: {
                    kind: latest.err ? 'error' : 'result',
                    result: latest.res || null,
                    error: latest.err || null,
                    log: {
                        level: 'debug',
                        data: {
                            kind: 'act',
                            case: 'CACHE',
                            cachetime: latest.when,
                        },
                    },
                },
            };
            ctx.cached$ = true;
            return out;
        }
    }
}
function inward_warnings(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var so = ctx.options;
    var msg = data.msg;
    if (so.debug.deprecation && ctx.actdef.deprecate) {
        ctx.seneca.log.warn({
            kind: 'act',
            case: 'DEPRECATED',
            msg: msg,
            pattern: ctx.actdef.pattern,
            notice: ctx.actdef.deprecate,
            callpoint: ctx.callpoint,
        });
    }
}
function inward_msg_meta(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var meta = data.meta;
    meta.pattern = ctx.actdef.pattern;
    meta.client_pattern = ctx.actdef.client_pattern;
    meta.action = ctx.actdef.id;
    meta.plugin = Object.assign({}, meta.plugin, ctx.actdef.plugin);
    meta.start = null == meta.start ? ctx.start : meta.start;
    meta.parents = meta.parents || [];
    meta.trace = meta.trace || [];
    var parent = ctx.seneca.private$.act && ctx.seneca.private$.act.parent;
    // Use parent custom object if present,
    // otherwise use object provided by caller,
    // otherwise create a new one.
    // This preserves the same custom object ref throughout a call chain.
    var parentcustom = (parent && parent.custom) || meta.custom || {};
    if (parent) {
        meta.parents = meta.parents.concat(parent.parents || []);
        meta.parents.unshift((0, common_1.make_trace_desc)(parent));
    }
    meta.custom = Object.assign(parentcustom, meta.custom, ctx.seneca.fixedmeta && ctx.seneca.fixedmeta.custom);
    // meta.explain is an array that explanation objects can be appended to.
    // The same array is used through the action call tree, and must be provided by
    // calling code at the top level via the explain$ directive.
    if (data.msg.explain$ && Array.isArray(data.msg.explain$)) {
        meta.explain = data.msg.explain$;
    }
    else if (parent && parent.explain) {
        meta.explain = parent.explain;
    }
    if (ctx.seneca.private$.explain) {
        meta.explain = meta.explain || [];
        ctx.seneca.private$.explain.push(meta.explain);
    }
}
function inward_prepare_delegate(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    const meta = data.meta;
    const plugin = ctx.seneca.private$.plugins[meta.plugin.fullname];
    if (plugin) {
        ctx.seneca.plugin = plugin;
        ctx.seneca.shared = plugin.shared;
    }
    ctx.seneca.fixedargs.tx$ = data.meta.tx;
    data.reply = data.reply.bind(ctx.seneca);
    data.reply.seneca = ctx.seneca;
    // const reply = data.reply
    // // DEPRECATE
    // ctx.seneca.good = function good(out: any) {
    //   ctx.seneca.log.warn(
    //     'seneca.good is deprecated and will be removed in 4.0.0'
    //   )
    //   reply(null, out)
    // }
    // // DEPRECATE
    // ctx.seneca.bad = function bad(err: any) {
    //   ctx.seneca.log.warn('seneca.bad is deprecated and will be removed in 4.0.0')
    //   reply(err)
    // }
    ctx.seneca.reply = function reply(err, out) {
        reply(err, out);
    };
    ctx.seneca.explain = intern.explain.bind(ctx.seneca, meta);
    if (meta.explain) {
        ctx.seneca.explain({ explain$: true, msg$: (0, common_1.clean)(data.msg) });
    }
}
function inward_sub(spec) {
    const ctx = spec.ctx;
    const data = spec.data;
    var meta = data.meta;
    var private$ = ctx.seneca.private$;
    // Only entry msg of prior chain is published
    if (meta.prior) {
        return;
    }
    var submsg = ctx.seneca.util.clean(data.msg);
    // Find all subscription matches, even partial.
    // Example: a:1,b:2 matches subs for a:1; a:1,b:1; b:1
    var sub_actions_list = private$.subrouter.inward.find(submsg, false, true);
    submsg.in$ = true;
    for (var alI = 0; alI < sub_actions_list.length; alI++) {
        var sub_actions = sub_actions_list[alI]; // Also an array.
        for (var sI = 0; sI < sub_actions.length; sI++) {
            var sub_action = sub_actions[sI];
            try {
                sub_action.call(ctx.seneca, submsg, null, data.meta);
            }
            catch (sub_err) {
                // DESIGN: this should be all that is needed.
                return {
                    op: 'stop',
                    out: {
                        kind: 'error',
                        code: 'sub_inward_action_failed',
                        error: sub_err,
                    },
                };
            }
        }
    }
}
intern.explain = function (meta, entry) {
    var orig_explain = this.explain;
    var explain = meta.explain;
    if (true === entry || false === entry) {
        return orig_explain.call(this, entry);
    }
    else if (explain) {
        if (null != entry) {
            if (entry.explain$) {
                entry.explain$ = {
                    start: meta.start,
                    pattern: meta.pattern,
                    action: meta.action,
                    id: meta.id,
                    instance: meta.instance,
                    tag: meta.tag,
                    seneca: meta.seneca,
                    version: meta.version,
                    gate: meta.gate,
                    fatal: meta.fatal,
                    local: meta.local,
                    direct: meta.direct,
                    closing: meta.closing,
                    timeout: meta.timeout,
                    dflt: meta.dflt,
                    custom: meta.custom,
                    plugin: meta.plugin,
                    prior: meta.prior,
                    caller: meta.caller,
                    parents: meta.parents,
                    remote: meta.remote,
                    sync: meta.sync,
                    trace: meta.trace,
                    sub: meta.sub,
                    data: meta.data,
                    err: meta.err,
                    err_trace: meta.err_trace,
                    error: meta.error,
                    empty: meta.empty,
                };
            }
            explain.push(entry && 'object' === typeof entry ? entry : { content: entry });
        }
    }
    return explain && this.explain;
};
let Inward = {
    inward_msg_modify,
    inward_closed,
    inward_act_cache,
    inward_act_default,
    inward_act_not_found,
    inward_validate_msg,
    inward_warnings,
    inward_msg_meta,
    inward_limit_msg,
    inward_act_stats,
    inward_prepare_delegate,
    inward_announce,
    inward_sub,
    intern,
};
exports.Inward = Inward;
//# sourceMappingURL=inward.js.map